我刚听完Scott Meyers关于C++0x的软件工程广播播客采访。大多数新特性对我来说都是有意义的,我现在对C++0x非常兴奋,只有一个例外。我仍然不懂移动语义。。。到底是什么?
当前回答
这就像复制语义,但不必复制所有数据,而是从“移动”的对象中窃取数据。
其他回答
假设您有一个返回实体对象的函数:
Matrix multiply(const Matrix &a, const Matrix &b);
当您编写这样的代码时:
Matrix r = multiply(a, b);
然后普通的C++编译器将为multiply()的结果创建一个临时对象,调用复制构造函数初始化r,然后销毁临时返回值。C++0x中的移动语义允许调用“移动构造函数”通过复制其内容来初始化r,然后丢弃临时值,而不必销毁它。
如果被复制的对象在堆上分配了额外的内存来存储其内部表示,这一点尤其重要(可能与上面的Matrix示例类似)。复制构造函数必须要么完整复制内部表示,要么在内部使用引用计数和写时复制语义。移动构造函数将不占用堆内存,只复制Matrix对象内的指针。
这就像复制语义,但不必复制所有数据,而是从“移动”的对象中窃取数据。
移动语义是指在没有人需要源值时转移资源,而不是复制资源。
在C++03中,对象经常被复制,只有在任何代码再次使用该值之前才会被销毁或赋值。例如,当您从函数中按值返回时,除非RVO踢入您返回的值,否则该值将被复制到调用方的堆栈帧,然后超出范围并被销毁。这只是众多示例中的一个:当源对象是临时对象时,请参阅passbyvalue;当超过其capacity()时,可以使用排序等算法重新排列项目。
当这种复制/销毁对很昂贵时,通常是因为对象拥有一些重量级资源。例如,vector<string>可能拥有一个动态分配的内存块,其中包含一个字符串对象数组,每个字符串对象都有自己的动态内存。复制这样的对象代价很高:必须为源中每个动态分配的块分配新的内存,并复制所有值。然后需要释放刚才复制的所有内存。然而,移动一个大向量<string>意味着只需将几个指针(指动态内存块)复制到目标,并在源中将它们清零。
你知道复制语义是什么意思吗?这意味着您有可复制的类型,对于用户定义的类型,您可以明确地编写复制构造函数和赋值运算符,或者编译器隐式地生成它们。这将复制一份。
移动语义基本上是一种用户定义的类型,带有构造函数,它接受一个非常量的r值引用(使用&&(是两个&符号)的新类型引用),这称为移动构造函数,赋值运算符也是如此。那么,移动构造函数做什么呢?它不是从源参数复制内存,而是将内存从源“移动”到目标。
你什么时候想这样做?那么std::vector就是一个例子,假设您创建了一个临时std::vector,然后从一个函数返回它,比如:
std::vector<foo> get_foos();
当函数返回时,复制构造函数将产生开销,如果(在C++0x中也是如此)std::vector有一个移动构造函数,而不是复制它。它只需要设置指针并将动态分配的内存“移动”到新实例。这有点像std::auto_ptr的所有权转移语义。
这是Bjarne Stroustrup的《C++编程语言》一书中的答案。如果你不想看视频,可以看下面的文字:
考虑一下这个片段。从运算符+返回涉及将结果从局部变量res复制到调用者可以访问的地方。
Vector operator+(const Vector& a, const Vector& b)
{
if (a.size()!=b.size())
throw Vector_siz e_mismatch{};
Vector res(a.size());
for (int i=0; i!=a.size(); ++i)
res[i]=a[i]+b[i];
return res;
}
我们真的不想要副本;我们只是想从函数中得到结果。所以我们需要移动Vector而不是复制它。我们可以如下定义移动构造函数:
class Vector {
// ...
Vector(const Vector& a); // copy constructor
Vector& operator=(const Vector& a); // copy assignment
Vector(Vector&& a); // move constructor
Vector& operator=(Vector&& a); // move assignment
};
Vector::Vector(Vector&& a)
:elem{a.elem}, // "grab the elements" from a
sz{a.sz}
{
a.elem = nullptr; // now a has no elements
a.sz = 0;
}
&&表示“右值引用”,是我们可以绑定右值的引用。“rvalue”'旨在补充“lvalue”,它大致意思是“可以出现在赋值左侧的值”。因此,rvalue大致意思是:“不能赋值的值”,例如函数调用返回的整数,以及Vectors运算符+()中的res局部变量。
现在,语句返回res;不会复制!
推荐文章
- cplusplus.com给出的错误、误解或坏建议是什么?
- 找出质数最快的算法是什么?
- c++枚举类可以有方法吗?
- 格式化IO函数(*printf / *scanf)中的转换说明符%i和%d之间的区别是什么?
- 将析构函数设为私有有什么用?
- main()中的Return语句vs exit()
- 为什么c#不提供c++风格的'friend'关键字?
- 在函数的签名中添加关键字
- 我如何在Visual Studio中预处理后看到C/ c++源文件?
- 为什么在标准容器中使用std::auto_ptr<>是错误的?
- 用比较double和0
- 保护可执行文件不受逆向工程的影响?
- 在c++中字符串前面的“L”是什么意思?
- 为什么std::map被实现为红黑树?
- 空括号的默认构造函数