【发布时间】:2012-01-15 14:38:39
【问题描述】:
我可能在这里感到困惑,但我确实理解的是:
- COW 将返回一个“假”副本,直到其中一个调用者想要进行一些修改。
- Move Semantic 在所有情况下都会返回“假”副本。
所以如果我的目的是拥有一个只需要读取而不需要更新的对象,我应该只等待我的 C++ 编译器中的移动语义支持?
我说的对吗?
【问题讨论】:
我可能在这里感到困惑,但我确实理解的是:
所以如果我的目的是拥有一个只需要读取而不需要更新的对象,我应该只等待我的 C++ 编译器中的移动语义支持?
我说的对吗?
【问题讨论】:
移动语义不会返回“假”副本。相反,在复制操作中,它授予复制者删除原始副本的权限。
一个激励性的例子可能是有启发性的:
std::vector<int> bigData;
// fill bigData
std::vector<std::vector<int> > listOfData;
listOfData.push_back(std::move(bigData));
// after this point, the contents of bigData are unspecified (however accessing it is _not_ undefined behavior)
如果没有移动语义,您需要复制bigData 以将其插入listOfData,或者手动将swap() 旋转到listOfData 中的新空向量中。但是使用移动语义,std::vector 的右值引用构造函数(又名移动构造函数)在复制新数据时由push_back 调用,有权丢弃bigData 的旧内容 - 因此,它是允许的例如,窃取bigData 的内部指针并将bigData 重置为空向量。
移动语义通常比 COW 语义更快,因为它们不需要维护对共享只读数据的引用计数。然而,它们受到更多限制 - 您无法使用移动语义为您的数据创建多个引用计数别名,您可以轻松方便地在容器之间打乱数据。
另请注意,最新版本的 GCC 和 Microsoft Visual C++ 都支持右值引用和移动语义(GCC 与 --std=c++0x),因此没有理由不立即开始使用它们。
【讨论】:
std::move 会退回到复制构造函数吗?或者也许在std::swap?
std::move 不会移动任何东西。它所做的只是将其转换为T&& r 值引用,这可以触发调用移动构造函数(或移动赋值运算符)。实际执行移动的是移动构造函数。将创建默认移动构造函数,就像默认复制构造函数一样。默认的移动构造函数会自行移动每个元素。对于基本类型,默认移动只是一个副本。对于用户定义的类型,它是对移动构造函数的调用。
copy-on-write 和 move 构造函数是不同的东西。
让我们谈谈 COW 实现很普遍的字符串。假设您有支持 COW 和移动语义的字符串实现。然后考虑这段代码:
cow::string foo() { return string("foo"); } // move CTOR is in effect here.
cow::string a = foo(); // move ctor in effect
cow::string b = a; // copy ctor in effect
a 和 b 这里将共享相同的分配字符序列。在这里
std::string foo() { return string("foo"); } // move CTOR is in effect here.
std::string a = foo(); // move ctor in effect
std::string b = a; // copy ctor in effect
a 和b 将分配并保存两个不同的字符序列,使内存消耗加倍。
【讨论】: