Почему std::vector использует конструктор перемещения, хотя и объявлен как noexcept(false)

Везде, где я читаю в Интернете, настоятельно рекомендуется, чтобы, если я хочу, чтобы мой класс хорошо работал с std::vector (т.е. семантика перемещения из моего класса использовалась std::vector) Мне следует переместить конструктор delcare как noexcept (или noexcept(true)).

Почему сделал std::vector использовать это, хотя я отметил это noexcept(false) как эксперимент?

#include <iostream>
#include <vector>
using std::cout;

struct T
{
    T() { cout <<"T()\n"; }

    T(const T&) { cout <<"T(const T&)\n"; }

    T& operator= (const T&)
    { cout <<"T& operator= (const T&)\n"; return *this; }

    ~T() { cout << "~T()\n"; }

    T& operator=(T&&) noexcept(false)
    { cout <<"T& operator=(T&&)\n"; return *this; }

    T(T&&) noexcept(false)
    { cout << "T(T&&)\n"; }
};

int main()
{
    std::vector<T> t_vec;
    t_vec.push_back(T());
}

выход:

T()
T(T&&)
~T()
~T()

Зачем? Что я сделал не так?

Скомпилировано в gcc 4.8.2 с CXX_FLAGS, установленным в:

--std=c++11 -O0 -fno-elide-constructors

2 ответа

Решение

Вы не сделали ничего плохого.

Вы просто ошибочно подумали push_back Пришлось избегать броска Move-Ctor: это не так, по крайней мере, для создания нового элемента.

Единственное место, где следует избегать бросания-перемещений / перемещений-назначений, - это перераспределение вектора, чтобы избежать перемещения половины элементов, а остальных на их исходных местах.

Функция имеет строгую гарантию исключительной безопасности:

Либо операция завершается успешно, либо происходит сбой, и ничего не изменилось.

Если vector::push_back необходимо перераспределить свою память, сначала она выделяет новую память, а затем перемещает конструирует новый элемент в последнюю позицию. Если это приводит к освобождению новой памяти, и ничего не изменилось, вы получите надежную гарантию безопасности исключений, даже если конструктор перемещения может выдать.

Если он не выбрасывает, существующие элементы переносятся из исходного хранилища в новое хранилище, и вот где noexcept спецификация конструктора перемещения имеет значение. Если при перемещении может возникнуть ошибка, а типом будет CopyConstructible, то существующие элементы будут скопированы, а не перемещены.

Но в вашем тесте вы только смотрите, как новый элемент вставляется в вектор, и всегда нормально использовать конструктор броска для этого шага.

Другие вопросы по тегам