Я попытался создать собственный распределитель памяти, который использует интеллектуальный указатель. Я не публикую код, потому что он слишком большой и не добавляет много информации. Затем я протестировал его с помощью std::vector
. Он отлично работает на Xcode. Но когда я попытался собрать тот же код в Visual Studio 12 (2013), сборка завершилась со следующей ошибкой:
... вектор (873): ошибка C2660: '
std::_Wrap_alloc< my_allocator< int > >::construct
': функция не принимает 2 аргумента
проблема в методе push_back:
void push_back(value_type&& _Val)
{
....
this->_Getal().construct(this->_Mylast,
_STD forward<value_type>(this->_Myfirst[_Idx]));
....
}
Сообщение об ошибке немного сбивает с толку. Настоящая проблема заключается в том, что this->_Mylast
имеет тип my_allocator< int >::pointer
, который является интеллектуальным указателем, а метод построения ожидает int*
.
Итак, вопрос прост: каковы требования к типам указателей, используемых в пользовательском распределителе памяти? Должен ли X::pointer
быть преобразован в необработанный указатель? Если да, то это делает их довольно бесполезными.
На самом деле я ожидал, что эта строка кода будет выглядеть так:
this->_Getal().construct(addressof(*(this->_Mylast)),
_STD forward<value_type>(this->_Myfirst[_Idx]));
Попробуем найти ответ в стандарте C++, который гласит:
[17.6.3.5-5] Распределитель типа X должен удовлетворять требованиям CopyConstructible (17.6.3.1). Типы
X::pointer
,X::const_pointer
,X::void_pointer
иX::const_void_pointer
должны удовлетворять требованиям NullablePointer (17.6.3.3). Никакой конструктор, оператор сравнения, операция копирования, операция перемещения или операция подкачки для этих типов не должны выходить через исключение.X::pointer
иX::const_pointer
также должны удовлетворять требованиям к итератору произвольного доступа (24.2).
Если мы посмотрим на требования NullablePointer, они добавят еще несколько требований:
[17.6.3.3] Тип NullablePointer — это тип, подобный указателю, который поддерживает нулевые значения. Тип P соответствует требованиям NullablePointer, если:
(1.1) — P удовлетворяет требованиям EqualityComparable, DefaultConstructible, CopyConstructible, CopyAssignable и Destructible...
Если я проверю требования к итератору произвольного доступа, я также не найду явного упоминания о его приведении к необработанному указателю. Но в нескольких местах используется подход с addressof
(например, 24.2.1-5).
Кроме того, это не единственное место в реализации Microsoft std::vector
, где предполагается, что X::pointer
и необработанный указатель равны. Мне интересно, что я пропустил?
РЕДАКТИРОВАТЬ: я добавлю здесь часть определения my_allocator:
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_pointer
и так далее? (Меня совершенно не удивит, если стандартная библиотека VC++ не будет полностью совместима) - person Columbo   schedule 25.12.2014std
содержащихся объектов должно выполняться черезallocator_traits::construct
, а не напрямуюallocator::construct
. - person Walter   schedule 25.12.2014