Lem*_*rop 20 c++ optional c++17
我很惊讶地得知移动构造函数(以及该事项的赋值)std::optional没有重置可选的移动,如[19.6.3.1/7]中所示,其中"bool(rhs)不变".
这也可以通过以下代码看出:
#include <ios>
#include <iostream>
#include <optional>
#include <utility>
int main() {
std::optional<int> foo{ 0 };
std::optional<int> bar{ std::move(foo) };
std::cout << std::boolalpha
<< foo.has_value() << '\n' // true
<< bar.has_value() << '\n'; // true
}
Run Code Online (Sandbox Code Playgroud)
这似乎与在标准库中移动的其他实例相矛盾,例如移动std::vector容器的位置通常以某种方式重置(在向量的情况下保证之后为空)以使其"无效",即使其中包含的对象也是如此他们自己已经离开了.这个或潜在的用例是否有任何理由支持,例如可能试图模仿相同类型的非可选版本的行为?
M.M*_*M.M 35
除非另行指定,否则类类型的移动对象将保持有效但未指定的状态.不一定是"重置状态",绝对不是"无效".
对于基本类型,移动与复制相同,即源不变.
具有原始成员的类类型的默认移动构造函数将移动每个成员,即保持原始成员不变; 用户定义的移动构造函数可能会也可能不会"重置"它们.
移动的向量可能或可能不包含其中的元素.我们期望它不会,因为那是有效的,但它不能依赖.
std::string由于小字符串优化,移动的可能仍然包含元素.
moveon std::optional实际上由标准指定(C++ 17 [optional.ctor]/7).它被定义为move对包含的类型进行操作(如果存在).它不会将有价值的可选项转换为无值的可选项.
因此,实际上预计您的代码输出true true,实际包含的值也foo应该保持不变.
关于为什么 std::optional移动构造函数是这样定义的问题:我不能肯定地说; 但是a optional不像最大大小为1的向量.它更像是一个带有有效性标记的变量.因此,移动a optional就像移动变量一样有意义.
如果optional向左移动旧的"空",那么a = std::move(b);将调用b托管对象的析构函数,这将是意外的(至少对我来说).
How*_*ant 24
总之:性能.
移动语义首先存在的主要动机之一是性能.因此,特殊操作移动构造和移动分配应尽可能快地适用于所有类型.
为了帮助实现这一目标,标准做法是将对象移动到有效但未指定的状态.因此,optional移动构造/赋值所需要做的最小的事情就是从源参数移动.要指定在移动后将源设置为没有值,则相当于:
搬家后,做一些额外的,不必要的工作.
无论额外工作多么小,它都是非零的.一些(我敢说很多)客户不需要额外的工作,也不应该付钱.需要它的客户可以x.reset()在移动后轻松添加,将移动optional到一个明确指定的状态.
| 归档时间: |
|
| 查看次数: |
1793 次 |
| 最近记录: |