Нет, кроме требования вектора не соблюдены
Технически, кроме указанного move c'tor, требуется, чтобы вектор использовал move вместо copy c'tor.
Я обнаружил, что это не относится к GCC 7.
std::vector<A> v;
v.push_back(A("555")); //triggers move c'tor
Вышеописанное работает до тех пор, пока A реализует move c'tor и задает move c'tor, так как noexcept не является необходимым.
Я хотел бы знать, если это проблема GCC или это нормально для всех компиляторов?
Или дело в том, что я что-то неправильно понимаю?
1 ответ
Стандарт не требует noexcept
переместить конструктор для T
чтобы использовать его при звонке std::vector<T>::push_back(T&&)
Вот что говорит стандарт push_back(T&& rv)
(см. [sequence.reqmts]):
Добавляет копию
rv
,
Требуется: T должно бытьMoveInsertable
вvector
].
MoveInsertible
это причудливая концепция, которая просто означает, что можно создать ваш тип с помощью ссылки на rvalue*. Например, через конструктор перемещения, но через конструкцию копирования это не выходит из уравнения.
Я думаю, что вы смешиваете это с фактом, что в зависимости от того, объявлен ли конструктор перемещения noexcept
или нет, std::vector
может сделать разные исключения исключения. См. "Замечания" для ссылки на значениеpush_back
([vector.modifiers]):
Примечания: ... Если исключение выдается не конструктором копирования, а конструктором перемещения, оператором присваивания или оператором присваивания перемещения
T
или любымInputIterator
операции нет никаких эффектов. Если исключение выдается при вставке одного элемента в конце иT
являетсяCopyInsertable
или жеis_nothrow_move_constructible<T>::value
являетсяtrue
Эффектов нет. В противном случае, если исключение выдается конструктором перемещенияCopyInsertable T
эффекты не уточняются.
* Чтобы быть более конкретным, является ли ваш тип MoveInsertible
в vector
или нет зависит от распределителя. То есть для распределителя A
вашей vector
, следующее должно быть правильно сформировано:
allocator_traits<A>::construct(m, p, rv)
m
это экземпляр вашего распределителяA
p
это указатель на ваш тип (T*
) (точнее сказать, это выровненное хранилище, которое может содержатьT
)rv
наше значение, которое мы пытаемся вставить (T&&
)