Why does std::vector use the move constructor although declared as noexcept(false)

早过忘川 提交于 2019-12-23 08:25:09

问题


Wherever I read in the internet, it is strongly adviced that if I want my class to be working well with std::vector (i.e. move semantics from my class were used by std::vector) I should delcare move constructor as 'noexcept' ( or noexcept(true) ).

Why did std::vector use it even though I marked it noexcept(false) as an experiment?

#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());
}

output:

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

Why ? What did I do wrong ?

Compiled on gcc 4.8.2 with CXX_FLAGS set to:

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

回答1:


You did nothing wrong.

You just wrongly thought push_back had to avoid a throwing move-ctor: It does not, at least for constructing the new element.

The only place where throwing move-ctors / move-assignments must be shunned is on re-allocation of the vector, to avoid having half the elements moved, and the rest in their original places.

The function has the strong exception-safety guarantee:

Either the operation succeeds, or it fails and nothing has changed.




回答2:


If vector::push_back needs to reallocate its storage it first allocates new memory, then move constructs the new element into the last position. If that throws the new memory is deallocated, and nothing has changed, you get the strong exception-safety guarantee even if the move constructor can throw.

If it doesn't throw, the existing elements are transferred from the original storage to the new storage, and here is where the noexcept specification of the move constructor matters. If moving might throw and the type is CopyConstructible then the existing elements will be copied instead of moved.

But in your test you're only looking at how the new element is inserted into the vector, and it is always OK to use a throwing constructor for that step.



来源:https://stackoverflow.com/questions/26224112/why-does-stdvector-use-the-move-constructor-although-declared-as-noexceptfals

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!