我可能有点混淆,但我的理解是:
- COW在没有任何调用者想要进行修改时返回一个“伪造”副本。
- 移动语义在所有情况下都会返回一个“伪造”副本。
因此,如果我只需要读取对象而不需要更新它,我应该等待我的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
中。但是有了移动语义,由push_back
调用的std::vector
的右值引用构造函数(也称为移动构造函数)在复制新数据时会授权销毁bigData
的旧内容-因此,它可以窃取bigData
的内部指针并将其重置为空向量。
移动语义通常比COW语义更快,因为它们不需要维护共享只读数据的引用计数。但是,它们更受限制-您不能使用移动语义创建对数据的多个引用计数别名,只能在容器之间轻松方便地移动数据。
还要注意,最近版本的GCC和Microsoft Visual C ++支持右值引用和移动语义(GCC使用--std=c++0x
),因此没有理由今天不开始使用它们。
复制-写入和移动构造函数是不同的东西。
让我们谈论一下广泛使用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
会分配并保存两个不同的字符序列,将内存消耗翻倍。
std::move
会退回到复制构造函数吗?或者退回到std::swap
? - Karl Knechtelstd::move
并不会移动任何东西,它只是将对象转换为T&&
右值引用类型,这可能会触发调用移动构造函数(或移动赋值运算符)。实际执行移动操作的是移动构造函数。就像默认的复制构造函数一样,默认的移动构造函数也会被创建。默认的移动构造函数会逐个元素地移动每个成员。对于基本类型,移动操作只是拷贝操作。对于用户定义类型,会调用移动构造函数。 - Nicol Bolas