I tried to create a custom memory allocator which uses a smart pointer. I do not post the code because it's too big and doesn't add much of information. Then I tested it with a std::vector. It works perfectly well on Xcode. But when I tried to build the same code in Visual Studio 12 (2013), the build failed with the following error:
...vector(873): error C2660: '
std::_Wrap_alloc< my_allocator< int > >::construct' : function does not take 2 arguments
the problem is in push_back method:
void push_back(value_type&& _Val)
{
....
this->_Getal().construct(this->_Mylast,
_STD forward<value_type>(this->_Myfirst[_Idx]));
....
}
The error message is a bit confusing. Real problem is that this->_Mylast is of type my_allocator< int >::pointer, which is a smart pointer, and construct method expects int*.
So, the question is simple: what are the requirements to pointer types used in a custom memory allocator? Should X::pointer be convertible to a raw pointer? If yes, it makes them pretty useless.
Actually I would expect that line of code to look like:
this->_Getal().construct(addressof(*(this->_Mylast)),
_STD forward<value_type>(this->_Myfirst[_Idx]));
Let's try to find an answer in C++ standard, which says:
[17.6.3.5-5] An allocator type X shall satisfy the requirements of CopyConstructible (17.6.3.1). The
X::pointer,X::const_pointer,X::void_pointer, andX::const_void_pointertypes shall satisfy the requirements of NullablePointer (17.6.3.3). No constructor, comparison operator, copy operation, move operation, or swap operation on these types shall exit via an exception.X::pointerandX::const_pointershall also satisfy the requirements for a random access iterator (24.2)
If we take a look at NullablePointer reqs, they add few other requirements:
[17.6.3.3] A NullablePointer type is a pointer-like type that supports null values. A type P meets the requirements of NullablePointer if:
(1.1) — P satisfies the requirements of EqualityComparable, DefaultConstructible, CopyConstructible, CopyAssignable, and Destructible...
If I check random access iterator requirements, I also don't find any explicit mentioning of its casting to a raw pointer. But in few places the approach with addressof is used (e. g. 24.2.1-5).
Also, it's not the only place in Microsoft's std::vector implementation where X::pointer and raw pointer are assumed to be equal. I'm wondering, what do I miss?
EDIT: I'll add a piece of my_allocator deffinition here:
class my_allocator
{
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef my_ptr<T> pointer;
typedef my_ptr<const T> const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
typedef my_ptr<void> void_pointer;
typedef my_ptr<const void> const_void_pointer;
<constructors>
pointer allocate(size_type n, const_void_pointer = nullptr);
void deallocate(const pointer& ptr, size_type elements_num);
};
const_pointerand so forth? (It would absolutely not surprise me if VC++' standard library is not fully compliant)stdcontained objects should be done viaallocator_traits::constructrather than directlyallocator::construct.