| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| ||||
| ||||
| Hello all C++ expert programmer, i have wrote partial general allocator for my container. After reading standard C++ library and code guru article, i have several questions. 1. Why allocator write forward declaration then allocation for void* rather than directly wrote allocator first ? Code: namespace std {
template <class T> class allocator;
// specialize for void:
template <> class allocator<void> {
public:
typedef void* pointer;
typedef const void* const_pointer;
// reference to void members are impossible.
typedef void value_type;
template <class U> struct rebind { typedef allocator<U>
other; };
};
template <class T> class allocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <class U> struct rebind { typedef allocator<U>
other; };
allocator() throw();
allocator(const allocator&) throw();
template <class U> allocator(const allocator<U>&) throw();
~allocator() throw();
pointer address(reference x) const;
const_pointer address(const_reference x) const;
pointer allocate(size_type,
allocator<void>::const_pointer hint = 0);
void deallocate(pointer p, size_type n);
size_type max_size() const throw();
void construct(pointer p, const T& val);
void destroy(pointer p);
};
}
2. What is the use/purpose of type definition ? Quote:
What i understand from here is because different container needs different pointer construct memory, therefore, there are different member data in list and vector. So, allocator need to match back its member data with vector for example. Quote:
Quote:
client(vector, list, map, set) ? Quote:
Code: template <class U>
struct rebind
{
typedef allocator<U> other;
};
list<int>;
interprete by compiler as list<int, allocator<int> >;
This code template <class T>
class allocator; is replace with allocator<int> >;
In other words, T(represent generic types) = int;
Then allocator class receive integer as argument
How compiler interpreter
template <class U>
struct rebind
{
typedef allocato<U> other;
}
How list is pass U ?
Please help me. I really appreciated any help. |
|
#2
| |||
| |||
| 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> >;
};
*/
|
|
#3
| |||
| |||
| You can not change or add code to std namespace because it is undefined behaviour. |
|
#4
| |||
| |||
| I didn't add to code to namespace standard. I create my custom allocator with my own namespace. Please behave in C++ usenet community. Thanks. |
|
#5
| |||
| |||
| Please help me. |
|
#6
| |||
| |||
| This is all my code. Code:
#ifndef _Custom_Allocator_
#define _Custom_Allocator_
#include <memory>
using std::allocator;
// ================================================
template <class T>
class MyAllocator
{
public:
// Type Definitions
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type; // Unsigned
// Signed
typedef ptrdiff_t difference_type;
// Member Function
MyAllocator(){}
// MyAllocator(const MyAllocator<T> &rhs);
~MyAllocator(){}
// MyAllocator<T>::rebind<U>::other;
template <class U>
struct rebind
{
typedef MyAllocator<U> other;
}
pointer address(reference memory) const
{
return *memory;
}
const_pointer address(const_reference memory) const
{
return *memory;
}
size_type MaxMemory()
{
return ;
}
pointer allocate(size_type allocateSiZe)
{
return ::operator new (allocateSize);
}
void deallocate(pointer aPtr, size_type allocateSize)
{
if (aPtr != 0)
{
destrory(aPtr);
::operator delete aPtr[allocateSize];
}
}
void construct(pointer aPtr, const_reference value)
{
if (aPtr != 0)
{
// ((void *)aPtr) is placement new
// T(value) convert to T type
::operator new ((void *)aPtr) T(value);
}
}
void destrory(pointer aPtr)
{
if (aPtr != 0)
{
*aPtr = 0;
}
}
};
/*
No refernce type to void* -That's why need
specialization for void.
*/
// ============== Global Functions ===============
template<class T1, class T2>
bool operator==(MyAllocator<T1>, MyAllocator<T2>) const
{
return MyAllocator<T1> == MyAllocator<T2>;
}
template<class T1, class T2>
bool operator!=(MyAlloc<T1>, MyAlloc<T2>) const
{
return MyAllocator<T1> != MyAllocator<T2>;
}
// ================================================
#endif
Thanks for your help. |
|
#7
| |||
| |||
| * PeterAPIIT@gmail.com: > This is all my code. Uhm, please specify the problem in the article's text, not only in the subject line. Subject line: "General Allocator Regarding type definitions and void * specialized problem" It would also be good with a little more detail about what the problem is. :-) > Code: > > #ifndef _Custom_Allocator_ > #define _Custom_Allocator_ Code:
Identifier starting with underscore followed by uppercase is reserved for the
implementation, don't use.
Also, preferentially use ALL UPPERCASE for macros (and generally not for other
identifiers, except where idiomatic such as T for template parameter).
> #include <memory>
>
> using std::allocator;
Don't use 'using' in a header file.
You're forcing client code to deal with name clashes.
> // ================================================
>
> template <class T>
> class MyAllocator
> {
> public:
>
> // Type Definitions
>
> typedef T value_type;
>
> typedef T* pointer;
> typedef const T* const_pointer;
>
> typedef T& reference;
> typedef const T& const_reference;
>
> typedef size_t size_type; // Unsigned
>
> // Signed
> typedef ptrdiff_t difference_type;
>
>
> // Member Function
>
> MyAllocator(){}
>
> // MyAllocator(const MyAllocator<T> &rhs);
> ~MyAllocator(){}
>
> // MyAllocator<T>::rebind<U>::other;
> template <class U>
> struct rebind
> {
> typedef MyAllocator<U> other;
> }
Missing semicolon.
Which means: this is not your actual code.
At least not a version that you've managed to compile.
> pointer address(reference memory) const
> {
> return *memory;
> }
Invalid operation.
Which means: this is not your actual code.
> const_pointer address(const_reference memory) const
> {
> return *memory;
> }
Invalid operation.
Which means: this is not your actual code.
> size_type MaxMemory()
> {
> return ;
> }
Invalid operation.
Which means: this is not your actual code.
> pointer allocate(size_type allocateSiZe)
> {
> return ::operator new (allocateSize);
> }
Misspelled name.
Which means: this is not your actual code.
> void deallocate(pointer aPtr, size_type allocateSize)
> {
> if (aPtr != 0)
> {
> destrory(aPtr);
> ::operator delete aPtr[allocateSize];
> }
> }
Misspelled name.
Which means: this is not your actual code.
> void construct(pointer aPtr, const_reference value)
> {
> if (aPtr != 0)
> {
> // ((void *)aPtr) is placement new
> // T(value) convert to T type
> ::operator new ((void *)aPtr) T(value);
> }
> }
Invalid syntax.
Which means: this is not your actual code.
> void destrory(pointer aPtr)
> {
> if (aPtr != 0)
> {
> *aPtr = 0;
> }
> }
Misspelled name.
Which means: this is not your actual code.
>
>
> };
>
> /*
> No refernce type to void* -That's why need
> specialization for void.
> */
>
> // ============== Global Functions ===============
>
> template<class T1, class T2>
> bool operator==(MyAllocator<T1>, MyAllocator<T2>) const
> {
> return MyAllocator<T1> == MyAllocator<T2>;
> }
Invalid operation.
Which means: this is not your actual code.
> template<class T1, class T2>
> bool operator!=(MyAlloc<T1>, MyAlloc<T2>) const
> {
> return MyAllocator<T1> != MyAllocator<T2>;
> }
Invalid operation.
Which means: this is not your actual code.
> // ================================================
>
>
>
> #endif
> > > What should i do for next steps ? You should stop thinking about defining your own allocator. Instead you should start with basics, learning C++ syntax and basic programming (expressions, loops, decisions, routines). A good C++ textbook will help with that. E.g. Glasborrow's "You can do it!", or, if you already know some programming (perhaps in some other language), "Accelerated C++". And when you run into some problem then, please post actual code that compiles. Cheers & hth., - Alf -- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail? |
|
#8
| |||
| |||
| I have corrected my code. Now my problem is this: Quote:
Code: #ifndef Custom_Allocator
#define Custom_Allocator
template <class T>
class MyAllocator
{
public:
// Type Definitions
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type; // Unsigned
// Signed
typedef ptrdiff_t difference_type;
// Member Function
MyAllocator(){}
template <class U>
MyAllocator(const MyAllocator<T> &rhs){}
~MyAllocator(){}
// MyAllocator<T>::rebind<U>::other;
template <class U>
struct rebind
{
typedef MyAllocator<U> other;
};
pointer address(reference memory) const
{
return &memory;
}
const_pointer address(const_reference memory) const
{
return &memory;
}
size_type max_size() const
{
return size_t(+99);
}
pointer allocate(size_type allocateSize)
{
return static_cast<pointer> (::operator new (allocateSize));
}
void deallocate(pointer aPtr, size_type allocateSize)
{
if (aPtr != 0)
{
destroy(aPtr);
::operator delete aPtr[allocateSize];
}
}
void construct(pointer aPtr, const_reference value)
{
if (aPtr != 0)
{
// ((void *)aPtr) is placement new
// T(value) convert to T type
::operator new ((void *)aPtr) T(value);
}
}
void destroy(pointer aPtr)
{
if (aPtr != 0)
{
aPtr->~MyAllocator<T>;
}
}
};
/*
No refernce type to void* -That's why need
specialization for void.
*/
// ============== Global Functions ===============
// Non member function cannot declare as constant
template<class T1, class T2>
bool operator==(MyAllocator<T1>& first, MyAllocator<T2>& second)
{
return first == second;
}
template<class T1, class T2>
bool operator!=(MyAllocator<T1>& first, MyAllocator<T2>& second)
{
return first!=second;
}
|
|
#9
| |||
| |||
| Code:
#ifndef Custom_Allocator
#define Custom_Allocator
template <class T>
class MyAllocator
{
public:
// Type Definitions
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type; // Unsigned
// Signed
typedef ptrdiff_t difference_type;
// Member Function
MyAllocator(){}
template <class U>
MyAllocator(const MyAllocator<T> &rhs){}
~MyAllocator(){}
// MyAllocator<T>::rebind<U>::other;
template <class U>
struct rebind
{
typedef MyAllocator<U> other;
};
pointer address(reference memory) const
{
return &memory;
}
const_pointer address(const_reference memory) const
{
return &memory;
}
size_type max_size() const
{
return size_t(+99);
}
pointer allocate(size_type allocateSize)
{
return static_cast<pointer> (::operator new (allocateSize));
}
void deallocate(pointer aPtr, size_type allocateSize)
{
if (aPtr != 0)
{
destroy(aPtr);
// ::operator delete aPtr[allocateSize];
}
}
void construct(pointer aPtr, const_reference value)
{
if (aPtr != 0)
{
// ((void *)aPtr) is placement new
// T(value) convert to T type
::operator new ((void *)aPtr) T(value);
}
}
void destroy(pointer aPtr)
{
if (aPtr != 0)
{
// aPtr->~MyAllocator<T>;
}
}
};
/*
No refernce type to void* -That's why need
specialization for void.
*/
// ============== Global Functions ===============
// Non member function cannot declare as constant
template<class T1, class T2>
bool operator==(MyAllocator<T1>& first, MyAllocator<T2>& second)
{
return first == second;
}
template<class T1, class T2>
bool operator!=(MyAllocator<T1>& first, MyAllocator<T2>& second)
{
return first!=second;
}
|
|
#10
| |||
| |||
| Please help me. |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.