c – 为什么移动构造函数和移动标准库的赋值运算符会使对象从未指定的状态移开?

在C标准库中有一个移动构造函数和移动赋值运算符的特殊描述,它表示数据移动的对象在调用后保持有效但未指定的状态.为什么?我坦白地说不明白.这是我直觉上没有想到的.真的,如果我在现实世界中从一个地方移动到另一个地方,我移动的地方是空的(是的,有效的),直到我搬到那里一些新东西.为什么在C世界应该有所不同?

例如,根据实现,以下代码

std::vector<int> a {1,2,3};
std::vector<int> b {4,5,6};
a = std::move(b);

可能等同于下一个代码

std::vector<int> a {1,6};
a.swap(b);

这真的是我没想到的.如果我将数据从一个向量移动到另一个向量,我期望向量移动数据为空(零大小).

据我所知,标准C库的GCC实现在移动后将向量保持为空状态.为什么不将此行为作为标准的一部分?

将对象保留为未指定状态的原因是什么.如果是为了优化,那也有点奇怪.我可以对未指定状态的对象做的唯一合理的事情是清除它(好吧,我可以得到向量的大小,我可以打印它的内容,但由于内容未指定,我不需要它).因此,对象将以任何方式由我手动或通过调用赋值运算符或析构函数清除.我更喜欢自己清除它,因为我希望它能被清除.但这是一个双重要求清除.优化在哪里?

解决方法

There is a special description for move constructors and move assignment operators in the C++ Standard Library that says that the object the data is moved from is left in a valid but unspecified state after the call. Why? I frankly don’t understand it. It is something I intuitively don’t expect. Really,if I move something from one place to another in the real world,the place I move from is left empty (and yep,valid),until I move there something new. Why in the C++ world should it be different?

事实并非如此.

但你没有考虑到“移动”并不总是一个举动.例如,从std :: array移动数据时会发生什么?不多.由于数组就地存储数据,因此没有交换指针,移动就成了副本.因此,虽然图书馆可能会破坏原始数据,但这样做并没有任何意义,所以标准不会比说“我们不保证你得到的”更进一步.

一个真实的例子是std :: string,它当前不将其内容存储在动态分配的内存块中,而是存储在一个小的自动分配的内存块中(这通常称为小字符串优化).像数组一样,没有办法真正“移动”这些信息;它必须被复制.该字符串可以在之后将其清零,并且可以将其长度减少到零,但是为什么要强制运行时对其用户造成损失呢?

因此,有可能在逐个案例的基础上对移动后的集装箱的状态做出更有力的保证,但只能通过人为限制实施(并减少优化机会),坦率地说没有充分的理由.

真实世界的类比可以作为一个思想实验很有趣,但使用它们来实际理解编程语言的行为是愚蠢的.

相关文章

对象的传值与返回说起函数,就不免要谈谈函数的参数和返回值...
从实现装饰者模式中思考C++指针和引用的选择最近在看...
关于vtordisp知多少?我相信不少人看到这篇文章,多半是来自...
那些陌生的C++关键字学过程序语言的人相信对关键字并...
命令行下的树形打印最近在处理代码分析问题时,需要将代码的...
虚函数与虚继承寻踪封装、继承、多态是面向对象语言的三大特...