Нет, кроме требования вектора не соблюдены

Технически, кроме указанного 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&&)
Другие вопросы по тегам