I have written a simple C++11 style stateful allocator type. Given
template<typename T> class my_allocator {
// the usual stuff
};
template<typename T> using my_vector = std::vector<T, my_allocator<T>>;
my_vector<int> x;
std::vector<int> y = x; // error
What is the best way to allow conversions from a my_vector
to a std::vector
using the default allocator? GCC 4.7 (recent svn) says
error: conversion from 'my_vector<int> {aka std::vector<int, my_allocator<int>>}' to non-scalar type 'std::vector<int>' requested
Obviously this could be done with, say, a simple conversion function such as
template<typename T> std::vector<T> to_std_vec(const my_vector<T>& v) {
return std::vector<T>(&v[0], &v[v.size()]);
}
but this seems pretty inelegant. Is there a better solution in C++11?
Move semantics are right out in this situation, of course, but I'd like copy construction and assignment to work without extra noise/typing.
You cannot possibly hope to get around the obvious copy: std::vector<int> y(x.begin(), x.end();
. The elements in y
will be allocated by the std::allocator
, while the elements in x
were allocated, and will be destroyed, by your own allocator. The two allocators could have entirely unrelated notions of memory and pointers! There's no reason that the memory storage that's used by one allocator is in any way related to that of the other.
What else then can you do but make a semantic element copy?
If you don't want the old container any more, you should do a move, though:
std::vector<int> y(std::make_move_iterator(x.begin()),
std::make_move_iterator(x.end()));
(This will help in case the elements have their own allocator which agrees. Not for int
, of course.)
Update: To reinforce the point, please note that the internal data buffer of a vector<T, Alloc>
is not of type T*
, but rather of type Alloc::pointer
. There's no reason that those are related types for two distinct allocators.
Hmm, I think your only option here is full copy like:
std::vector<int> y( x.begin(), x.end());
There are 3 solutions to your problem:
I. If your vector 'y' does not exist yet, you could use :
std::vector<int> y(x.begin(), x.end());
II. If your vector 'y' already exist, you could use : (e.g. for a member of a class)
this->y.assign(x.begin(), x.end());
These 2 ways to fill a vector are not looking the container type. (and therefore the allocator type)
III. Another solution is to create a parent class which could be used as an allocator adapter between the std allocator and your own allocator. In this case, your 2 allocators are of the same type, and could be used with vector methods like operator=().