Why does resize() cause a copy, rather than a move, of a vector's content when capacity is exceeded? [duplicate]

故事扮演 提交于 2019-12-04 03:43:09
Andy Prowl

Paragraph 23.3.6.3/14 of the C++11 Standard specifies (about the resize() member function of the vector<> class template):

Remarks: If an exception is thrown other than by the move constructor of a non-CopyInsertable T there are no effects.

In other words, this means that for X (which is CopyInsertable), resize() offers the strong guarantee: it either succeeds or leaves the state of the vector unchanged.

In order to satisfy this guarantee, implementations usally adopt the copy-and-swap idiom: if the copy constructor of X throws, we haven't altered the content of the original vector yet, so the promise is kept.

However, if the previous content of the vector were moved into the new storage rather than being copied and the move constructor threw, then we would have irreversibly changed the original content of the vector.

Therefore, implementations will use the copy constructor of X to safely transfer the content of the vector into a new storage unless the move constructor is known not to throw, in which case it is safe to move from the previous elements.

With a small change to the definition of X's move constructor (marking it as noexcept), in fact, the output of the program is now the expected one.:

struct X
{
    X() { }
    X(int) { }
    X(X const&) { std::cout << "X(X const&)" << std::endl; }
    X(X&&) noexcept { std::cout << "X(X&&)" << std::endl; }
//         ^^^^^^^^
};

Think about the exception guarantees: If there's an exception during the reallocation, the vector has to remain unchanged. This can only be guaranteed by copying the elements and retaining the old set until the entire copy has succeeded.

Only if you know that the move constructor doesn't throw can you safely move the elements to the new location. To achieve this, declare the move constructor noexcept.

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