General Allocator Regarding type definitions and void * specializedproblem

P

PeterAPIIT

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 ?

1. A couple of type definitions. These ensure that the allocators'
client (for instance, 'std::vector') is able to use some relevant
types by known names. For example, consider that you write an
allocator, that is able to allocate memory in a far area, that cannot
be reached by normal pointers (let your imagination wander). Now, the
'allocator' will use some pointer-like construct. The allocators'
client has, of course, no idea of such a thing. When a client needs to
pass such a pointer it will use the

typedef T* pointer;

and if it needs to suptract such pointers, the result will have the
type 'difference_type', whatever that internally means for the
allocator.


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.

typedef T* pointer; ----------- Allocator

Vector
typedef A allocator_type; typedef typename A::pointer pointer;

Although, i not able to understand what this does

vector
typedef A allocator_type; typedef typename A::pointer pointer;

3. How allocator know when it need rebind for its allocator
client(vector, list, map, set) ?

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> >
:ther instead.


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 ?

Thanks for your help.

Please help me.
I really appreciated any help.
 
P

PeterAPIIT

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> >;

};

*/

Thanks for your correction.
 
A

Ali Karaali

You can not change or add code to std namespace because it is
undefined behaviour.
 
P

PeterAPIIT

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.
 
P

PeterAPIIT

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

What should i do for next steps ?

Thanks for your help.
 
P

PeterAPIIT

I have corrected my code.

Now my problem is this:

Error 1 error C2440: 'default argument' : cannot convert from
'MyAllocator<T>' to 'MyAllocator<T>' c:\program files\microsoft visual
studio 8\vc\include\list 83

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;
}

Please help me.
 
P

PeterAPIIT

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;
}

This is my code so far.
 
T

Thomas J. Gritzan

template <class T>
class MyAllocator
{
public:

// Type Definitions

typedef T value_type; [...more types...]

// Member Function

MyAllocator(){}

template <class U>
MyAllocator(const MyAllocator<T> &rhs){}
^^^
The template parameter U is not used. Do you mean this instead?

template <class U>
MyAllocator(const MyAllocator<U> &rhs){}


[...]
// ============== Global Functions ===============

// Non member function cannot declare as constant

You cannot declare the functions as constant, but the parameter:
template<class T1, class T2>
bool operator==(MyAllocator<T1>& first, MyAllocator<T2>& second)

bool operator==(const MyAllocator said:
{
return first == second;

What function should be called here? The function will call itself. This
is infinite recursion.
}

template<class T1, class T2>
bool operator!=(MyAllocator<T1>& first, MyAllocator<T2>& second)
{
return first!=second;
}

Same as above.
 
P

PeterAPIIT

Why cannot use "using" in header file ?

how do resolve the operator == and operator!= ?

Thanks for your help.
 
P

PeterAPIIT

Another error is

Error 1 error C2146: syntax error : missing ';' before identifier
'aPtr' d:\c++\custom allocator\custom allocator\custom_allocator.h 87
Warning 2 warning C4551: function call missing argument list d:\c++
\custom allocator\custom allocator\custom_allocator.h 87

for this code

Code:
void deallocate(pointer aPtr, size_type allocateSize)
	{
		if (aPtr != 0)
		{
			destroy(aPtr);
			::operator delete aPtr[allocateSize];
		}
	}


This is my complete code:

Code:
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<U> &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;
}



Please correct me if i wrong.

A billion thanks for your help.
 
E

Erik Wikström

Why cannot use "using" in header file ?

Since you have not quoted the part you are replying to I can only guess
you meant "why can I not use "using namespace" in a header file?" and
the answer is that you can, but it is bad. The reason is simple, every
file that included your header will get the effects of the "using
namespace", consider the following:

------ Test.h -----

#ifndef TEST_H
#define TEST_H

#include <iostream>

using namespace std;

void foo()
{
std::cout << "foo()\n";
}

#endif

------ Test.cpp -----

#include <vector>

#include "Test.h"

template<typename T>
class vector
{
T t;
};

int main()
{
vector<int> v; // Error
}

The problem is that the "using namespace std;" in Test.h" is in effect
in Test.cpp, and vector<int> can now refer to your class or std::vector.
In some cases you might get even worse problems because you do not get
an ambiguity and instead you use some type/function which you did not
intend to use, and the only clue is that the program does not work as it
should.

Therefore you should avoid "using namespace" in headers.
 
P

PeterAPIIT

"why can I not use "using namespace" in a header file?"


Are you trying to explain that name clashed between user defined code
and standard namespace ?

After listen to you advise, i guess we can include any header file in
our own header file but cannot using whole namespace instead explicit
specify which function or class to use.

In the example you given, compiler cannot resolve vector defined by us
ans std. Therefore, an ambiguity has occurred.

Am i correct ?


Another question is how about code at below ?

Code:
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>;
		}
	}

template<class T1, class T2>
bool operator==(const MyAllocator<T1>& first,
				const MyAllocator<T2>& second)
{
	return true;
}

template<class T1, class T2>
bool operator!=(const MyAllocator<T1>& first,
				const MyAllocator<T2>& second)
{
	return false;
}


What code is need to add ?


A billion thanks for your help.
 
P

PeterAPIIT

Yet another question is when i try to compile my code.

It shown my error :

Code:
void destroy(pointer aPtr)
	{
		if (aPtr != 0)
		{
			aPtr->~MyAllocator<T>;
		}
	}

error C2325: 'MyAllocator<T>' : unexpected type to the right of '->~':
expected 'std::_List_nod<_Ty,_Alloc>::_Node '


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);
		}
	}

error C2665: 'operator new' : none of the 5 overloads could convert
all the argument types
error C2146: syntax error : missing ';' before identifier 'T'



void deallocate(pointer aPtr, size_type allocateSize)
	{
		if (aPtr != 0)
		{
			destroy(aPtr);
			::operator delete aPtr[allocateSize];
		}
	}

error C2146: syntax error : missing ';' before identifier 'aPtr'
warning C4551: function call missing argument list


A billion thanks for your help.
 
P

PeterAPIIT

This is my intention of my code

Code:
void deallocate(pointer aPtr, size_type allocateSize)
	{
		if (aPtr != 0)
		{
			destroy(aPtr);
// 			::operator delete aPtr[allocateSize];

// I want delete the memory of container
		}
	}

	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);

// I want to do placement new to initialize the memory which has
allocated
		}
	}
	void destroy(pointer aPtr)
	{
		if (aPtr != 0)
		{
			aPtr->~MyAllocator<T>;
// I want to do uninitialize the container value hold.

}
	}


A billion thanks for your help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top