为何对const std::optional中的值执行std::move是合法的?
关于这段C++代码的疑问解答
先看你给出的代码:
#include <optional> #include <vector> #include <iostream> int main() { std::vector<int> v{1, 2, 3}; const std::optional<std::vector<int>> ov = v; const auto nv = std::move(ov.value()); for (const auto& x : *ov) { std::cout << x; } for (const auto& x : nv) { std::cout << x; } }
输出为123123,针对你的两个疑问解答如下:
疑问1:为何对const std::optional中的值执行std::move是合法的?
std::move本质只是一个类型转换工具,它不会实际执行移动操作,仅负责把传入表达式的值类别从左值转换成右值。
这里ov是const std::optional<std::vector<int>>,调用ov.value()会返回const std::vector<int>&(const左值引用)。std::move作用在这个const左值上,会将其转换为const std::vector<int>&&(const右值引用)——这个类型转换是C++标准允许的,所以代码本身合法。
但要注意:这种转换并不会触发真正的移动,因为vector的移动构造函数要求参数是非const的右值引用(std::vector<int>&&),const右值引用无法匹配这个构造函数。
疑问2:为何optional ov仍持有vector?
因为这段代码根本没发生移动,而是执行了拷贝操作:
- 当你写
const auto nv = std::move(ov.value());时,std::move(ov.value())得到的是const std::vector<int>&&,它无法匹配vector的移动构造函数,只能匹配拷贝构造函数std::vector(const std::vector&)。 - 拷贝构造只会复制源对象的内容,不会修改源对象,所以
ov内部的vector完全不受影响,仍然持有原来的元素。
因此遍历*ov和nv都会输出123,最终得到123123的结果。
内容的提问来源于stack exchange,提问作者Markus Moll
相关产品推荐
相关产品推荐

