Re: General Allocator Regarding type definitions and void *
specialized problem
This is current work.
[code]
/*
Two steps define custom allocators
1. Design a memory management mechanism/model
2. Create standard-like allocators
*/
// ================================================
#ifndef _Custom_Allocator_
#define _Custom_Allocator_
#include <memory>
using std::allocator;
// ================================================
template <class T>
class MyAlloc
{
// Two Constructos which did nothing
public:
// Type Definitions
// Pointer to element type used in memory model
typedef T* pointer;
// Const Pointer to element type used in memory model
typedef const T* const_pointer;
// Reference to element type used in memory model
typedef T& reference;
typedef const T& const_reference;
// Type of the element that is being used in the memory model
typedef T value_type;
// Rpresent largest object in allocator memory model
typedef size_t size_type; // Unsigned
// Represent two pointer in two allocator model
typedef ptrdiff_t difference_type; // Signed
// =================================================
// Member Function
/*
No throw is allowed for constructor
and destructor
C && D is trivial(Not important)
*/
MyAlloc();
/*
Copy C is need because exception
specification stated that constructor
is not allow to throw.
Does require operator= because
if (this != rhs) then code will not
be executed and Two MyAlloc object must
same which form by C++ standard allocator
*/
MyAlloc(const MyAlloc<T> &);
~MyAlloc();
/*
Require rebind because list(nodes), vector
(contigious)
Rebind is a structure that enables
an allocator for objects of one type
interpret as to allocate storage for
objects of another type.
To allocate objects of
different types than its
template parameter
The rebind member allows a container
to construct an allocator for some
arbitrary type out of the allocator type
provided as a template parameter.
This is the magic required
for std::list to work properly,
since given std::list<int>
( allocator<int>() ),
std::list actually needs to allocate memory
for Node<int>, and not int.
Thus, they need to rebind to
allocator<int>()::rebind<Node<int> >
::other instead.
For instance, the list container gets an
allocator<T> by default, but a list may
well need to allocate list_nodes as well
as T's. The container can construct an
allocator for list_nodes out of the
allocator for T's
(the template parameter,
Allocator, in this case) as follows:
Allocator::rebind<list_node>
::other list_node_allocator;
*/
/*
Explicit call by compiler is
allocator<T>::rebind<U>::other;
Here allocator client(vector, list)
request allocator type from allocator
Therefore, allocator using rebind to
preseve the old state type and duplicate
a same/new state type to pass to
allocator client.
Then, continue to class to rework a new
type which is
listAllocator < node<int> > and
not allocator<int>.
*/
template <class U>
struct rebind
{
typedef allocator<U> other;
}
// Return address of given object
pointer address(reference x) const;
const_pointer address(const_reference x) const;
// Returns the largest value which can be passed to the 'allocate()'
function.
size_type MaxMemory();
/*
Returns storage for n elements of
the element type being used
in the memory model.
Elements will not be c
onstructed/initialized.
*/
pointer allocate(size_type);
/*
Deallocate element type used in
memory model begin at position p
Storage must be allocate by same allocator
Size must same in allocate()
p must not be 0.
Elements must have been destroyed before.
*/
void deallocate(pointer, size_type);
/*
Allocate must call before construct
This is a call to placement new
value is U
new((void*)p) T(u);
*/
void construct(pointer, const_reference);
/*
Destrory call ahead of (prior to) deallocate
new((void*)p) T(u);
*/
void destrory(pointer);
};
/*
No refernce type to void* -That's why need
specialization for void.
*/
// ================================================
template<class T1, class T2>
bool operator==(MyAlloc<T1>, MyAlloc<T2>) const
{
return MyAlloc<T1> == MyAlloc<T2>;
}
template<class T1, class T2>
bool operator!=(MyAlloc<T1>, MyAlloc<T2>) const
{
return MyAlloc<T1> != MyAlloc<T2>;
}
// ================================================
#endif
/*
allocate and deallocate function are
low level memory management which
doesn't participate in
object construction and destruction.
The purpose of the allocator is to allocate
raw memory without construction of objects,
as well as simply deallocate memory
without the need to destroy them.
Usage of ::operator new and ::operator delete
is preferred over keywords new and delete.
A* a = new A;
delete a;
Intepreted by compiler as below:
// assuming new throws std::bad_alloc upon failure
Allocate then construct
A* a = ::operator new(sizeof(A));
a->A::A();
if ( a != 0 )
{ // a check is necessary for delete
a->~A();
::operator delete(a);
Destroyed(Destruct) first
before deallocate
}
Every C++ standard like allocator must provide
these global operator== and operator!=
Memory Model are shared model, grabage collection,
segregrated model.
Why write custom allocators ?
1. To trace the memory operations of
your application to a file
2. Speed
Sample Override New and delete Code
void* operator new(size_t,void* anAddress)
{
return anAddress;
}
void* operator new(size_t size)
{
return Standard::Allocate(size);
}
void operator delete(void *anAddress)
{
if (anAddress)
Standard::Free((Standard_Address&)anAddress);
}
The first new operator overload is for the
new with placement syntax, instead of
creating instances on the free store it
will use the address you provided.
This is useful for using preallocated memory (e.g. a buffer)
to store your objects and still have the
construtors and destructors called for these
objects.
Apparently this first overload is just the
default one that would be generated by
the compiler anyway.
The second new and the delete operator overload are apparently
defined because the coder wanted to use a custom allocator.
If the first new overload seems useless but is still present it may
be that the compiler is requiring it if you overload the new(size_t)
one ( just a guess), try removing the new(size_t, void*) definition
and see if the code still compiles and link.
No reference to object which allocated on the stack
This is make sense since stack unwinding
will get clean up and you will use danling
reference
Never pass auto_ptrs by value
if a function can throw
BTW, returning auto_ptrs by value is a
good idea for factory and
clone like functions.
*/
// Sketch version of list
/*
template <typename T, typename A>
class node
{
typedfed node list_nodes;
typename A::rebind<list_nodes>::others listNodeAllocator;
// Actually declare listNodeAllocator < list_nodes<T> >;
};
*/
[/code]
Thanks for your correction.