-
March 4th, 2012, 12:18 PM
#1
Custom allocator problems
Does anyone know if the requirements have changed for writing custom allocators with C++ 0x11?
A custom allocator (that uses a fixed array as its memory pool) that I have been using successfully for some time, now throws an exception!
It runs fine under VS2008 but bombs out with VS2010.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
March 4th, 2012, 02:29 PM
#2
Re: Custom allocator problems
While I don't think the requirements have been changed, there is now an allocator_traits which you are supposed to use, rather than calling the allocator directly. How this affects existing code though... I'm not sure.
Theory says that changes to C++11 shouldn't break existing C++ code...
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
March 4th, 2012, 04:10 PM
#3
Re: Custom allocator problems
It appears to get upset whilst traversing a linked list, where it comes across an unititialised pointer.
Code:
// MEMBER FUNCTIONS FOR _Container_base12
inline void _Container_base12::_Orphan_all()
{ // orphan all iterators
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myproxy != 0)
{ // proxy allocated, drain it
_Lockit _Lock(_LOCK_DEBUG);
for (_Iterator_base12 **_Pnext = &_Myproxy->_Myfirstiter;
*_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter)
(*_Pnext)->_Myproxy = 0;
_Myproxy->_Myfirstiter = 0; <<<< Here
}
#endif /* _ITERATOR_DEBUG_LEVEL == 2 */
}
In this case, the allocator has been applied to a std::vector. The exception occurs when calling 'reserve'.
Code:
vector<int, ArrayAllocator<int, 10>> test;
int main()
{
test.reserve(2);
}
I'll give allocator_traits a look.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
March 5th, 2012, 05:06 AM
#4
Re: Custom allocator problems
I don't seem to be able to get to the bottom of this yet.
Here's a demo that compiles correctly with both VS2008 & VS2010, but exceptions under VS2010.
The allocator shown is a simplified version which only works with items that have a trivial destructor.
All of the tests should print 'true'.
Code:
#include <vector>
#include <iostream>
using namespace std;
template <typename T, const size_t MAX_SIZE>
class ArrayAllocator
{
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef std::ptrdiff_t difference_type;
//*********************************************************************
template <typename U>
struct rebind
{
typedef ArrayAllocator<U, MAX_SIZE> other;
};
//*********************************************************************
ArrayAllocator()
{
}
//*********************************************************************
ArrayAllocator(const ArrayAllocator &rhs)
{
std::copy(rhs.buffer, rhs.buffer + MAX_SIZE, buffer);
}
//*********************************************************************
template <typename U>
ArrayAllocator(const ArrayAllocator<U, MAX_SIZE> &rhs)
{
}
//*********************************************************************
pointer address(reference x) const
{
return (&x);
}
//*********************************************************************
const_pointer address(const_reference x) const
{
return (x);
}
//*********************************************************************
pointer allocate(size_type n,
const_pointer cp = 0)
{
// Too big?
if (n > MAX_SIZE)
{
throw std::bad_alloc();
}
// Return the beginning of the buffer.
return buffer;
}
//*********************************************************************
void deallocate(pointer p,
size_type n)
{
}
//*********************************************************************
size_type max_size() const
{
return (MAX_SIZE);
}
//*********************************************************************
void construct(pointer p,
const value_type &x)
{
*p = x;
}
//*********************************************************************
void destroy(pointer p)
{
p->~value_type();
}
private:
// Disabled operator.
void operator =(const ArrayAllocator &);
// The allocation pool.
T buffer[MAX_SIZE];
};
//*********************************************************************
template <typename T, const size_t MAX_SIZE>
inline bool operator ==(const ArrayAllocator<T, MAX_SIZE> &,
const ArrayAllocator<T, MAX_SIZE> &)
{
return (false);
}
//*********************************************************************
template <typename T, const size_t MAX_SIZE>
inline bool operator !=(const ArrayAllocator<T, MAX_SIZE> &,
const ArrayAllocator<T, MAX_SIZE> &)
{
return (true);
}
//*********************************************************************
int main()
{
const size_t MAX_SIZE = 10;
std::vector<int, ArrayAllocator<int, MAX_SIZE>> test;
cout << std::boolalpha << (test.size() == 0) << "\n";
cout << std::boolalpha << (test.max_size() == MAX_SIZE) << "\n";
cout << std::boolalpha << (test.capacity() == 0) << "\n";
test.push_back(1); // Exception here for VS2010.
test.push_back(2);
cout << std::boolalpha << (test[0] == 1) << "\n";
cout << std::boolalpha << (test[1] == 2) << "\n";
cout << std::boolalpha << (test.size() == 2) << "\n";
cout << std::boolalpha << (test.max_size() == MAX_SIZE) << "\n";
cout << std::boolalpha << (test.capacity() == 2) << "\n";
test.reserve(5);
cout << std::boolalpha << (test.size() == 2) << "\n";
cout << std::boolalpha << (test.max_size() == MAX_SIZE) << "\n";
cout << std::boolalpha << (test.capacity() == 5) << "\n";
}
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
March 5th, 2012, 05:49 AM
#5
Re: Custom allocator problems
the allocator requirements ( both in c++11 and c++2003 ) basically imply that the allocator instance cannot "contain" the memory used for allocation, because given two instances a,b of the same (or rebinded) allocator type, a==b implies that b can deallocate what a has previously allocated and vice versa. Hence, your allocator will break whenever the container uses (legally) more then one "rebind" of your passed allocator type.
Indeed, in the vs2010 vector ctor code there is
Code:
{ // construct allocator from _Al
typename _Alloc::template rebind<_Container_proxy>::other
_Alproxy(_Alval);
this->_Myproxy = _Alproxy.allocate(1);
_Cons_val(_Alproxy, this->_Myproxy, _Container_proxy());
this->_Myproxy->_Mycont = this;
_Myfirst = 0;
_Mylast = 0;
_Myend = 0;
}
as you can see, your allocator is returning a pointer to a memory region to be destroyed at scope exit, hence the error. This doesn't happen in vs2008 just by chance, because only one allocator instance is used throughout the container lifetime ( allocator<T> for std::vector, allocator<T>::rebind<Node<T>>:ther for std::list etc... )
Stack based allocators should use an external stack space instead, a so called "memory arena" ...
Last edited by superbonzo; March 5th, 2012 at 05:51 AM.
-
March 5th, 2012, 06:41 AM
#6
Re: Custom allocator problems
Originally Posted by superbonzo
, a==b implies that b can deallocate what a has previously allocated and vice versa.
I understand what you're saying, but I understood that the purpose of the == and != operators was to inform the container code whether allocators were equivalent or not, and so take appropriate action. a==b in the case of this allocator would be false.
I'm programming in a real-time embedded environment and the purpose of the array allocators was to allow use of STL containers in a more deterministic manner.
Oh well, time to roll up the sleeves and refactor.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
March 6th, 2012, 12:04 PM
#7
Re: Custom allocator problems
Originally Posted by JohnW@Wessex
Here's a demo that compiles correctly with both VS2008 & VS2010, but exceptions under VS2010.
I didn't test it, but wouldn't the solution be to take the buffer out of the allocator? Something like
Code:
int main()
{
const size_t MAX_SIZE = 1024; // bytes
char buffer[MAX_SIZE];
std::vector<int, ArrayAllocator<int, MAX_SIZE>> test(
ArrayAllocator<int, MAX_SIZE>(buffer));
//...
}
where the buffer is passed to the allocator's constructor.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
March 7th, 2012, 04:12 AM
#8
Re: Custom allocator problems
I think I've tried some variations of that, given superbonzo's comments , but I'll give it a second look.
Whenever I've put together an allocator that returns the same address as previously (which in theory should be perfectly valid for a vector of objects with trivial destructors, as I don't actually have to allocate more memory and move any data, just let it use more of the original array), VS2010 exceptions.
An experimental bodge that returned the last address+1 at every call kept it happy. (though of course it wasn't a solution)
I even tried alternating between two arrays to no avail.
It seems to expect that all allocations will be at new and unique addresses.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|