vector::push_back使用std::move进行内部重新定位



类型X有一个非平凡的移动构造函数,它不是声明的noexcept(即它可以抛出(:

#include <iostream>
#include <vector>
#include <memory>

struct X {
X()=default;
X(X&&) { std::cout << "X move constructedn"; } // not 'noexcept'
X(const X&) { std::cout << "X copy constructedn"; }
};
struct test {
X x;
};
int main()
{
static_assert(std::is_nothrow_move_constructible_v<X> == false);
static_assert(std::is_nothrow_move_constructible_v<test> == false);
std::vector<test> v(1);
v.push_back(test{}); // internal object re-allocation, uses copy-constructor
}

vector<test>上调用push_back时,内部重新分配会导致复制现有对象,这是意料之中的事。输出为:

X move constructed
X copy constructed

显然,第二行与内部对象重新分配有关。

现在,一个不相关的std::unique_ptr<int>被添加到test:

struct test {
std::unique_ptr<int> up;
X x;
};

输出变为:

X move constructed
X move constructed

为什么这次内部重新分配使用move构造函数
从技术上讲,X(X&&)仍然可以抛出异常;这不会违反push_back的强异常保证吗?

编译器是gcc 11.2.1和/或clang 12.0.1

根据[vector.modifiers]/2,如果std::vector的元素类型不可复制插入,也不可nothrow移动构造,则该元素类型的移动构造函数抛出的异常会导致容器处于未指定状态。

如果类型不是另一行可移动的,std::vector必须更喜欢复制构造函数,以便可以保留异常保证,但如果这不可能,则不可能提供强异常保证。

最新更新