为何std::pair允许从含删除移动构造的类右值初始化?
为什么std::pair允许从不可移动类型的右值初始化?
首先看这个不可移动类型的定义:
struct Do_not_move { Do_not_move() = default; Do_not_move(const Do_not_move&) = default; Do_not_move(Do_not_move&&) = delete; private: int dummy; };
我们会发现一个有意思的现象:
std::pair<int, Do_not_move> p(0, std::move(dnm));这段代码能正常运行- 但像
std::vector<Do_not_move> v{std::move(dnm)};、std::set<Do_not_move> s{std::move(dnm)};、std::any a{std::move(dnm)};这类代码都会报错
那为啥std::pair这么特殊?
其实核心原因在于std::pair的构造函数参数处理逻辑:
当你用std::move(dnm)作为参数传给std::pair的构造函数时,虽然你传的是右值,但std::pair的构造函数并不会强制要求用移动构造来初始化它的成员。它会把传入的第二个参数(类型是Do_not_move&&)绑定到构造函数的参数上,然后在初始化pair的Do_not_move成员时,因为Do_not_move的移动构造被删除了,编译器会自动退而求其次,调用可用的拷贝构造函数——而这个类型的拷贝构造是默认存在的,所以整个初始化过程能正常完成。
而像vector、set这类容器,它们在处理初始化元素的时候,会尝试直接用传入的右值来构造容器内的元素,也就是会优先调用移动构造函数。一旦移动构造被删除,编译器找不到可用的构造方式,自然就报错了。std::any也是类似的逻辑,它在存储对象时会尝试移动构造,失败就会直接报错。
简单总结一下:std::pair的构造函数没有强制绑定传入参数的值类别(左值/右值)来构造成员,而是允许编译器根据可用的构造函数自动选择最优方案;而其他容器/工具类则会更严格地按照传入值的类型来尝试构造,当移动不可用时就直接失败。
内容的提问来源于stack exchange,提问作者xskxzr
相关产品推荐
相关产品推荐

