系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
18.2.3 移动构造函数解析
虽然使用右值引用可支持移动语义,但这并不会神奇地发生。要让移动语义发生,需要两个步骤。首先,右值引用让编译器知道何时可使用移动语义:
Useless two one;/matches Useless::Useless(const Useless &)
Useless four(one +three)://matches Useless::Useless(Useless &&)
对象 one是左值,与左值引用匹配,而表达式one+three是右值,与右值引用匹配。因此,右值引用让编译器使用移动构造函数来初始化对象four。实现移动语义的第二步是,编写移动构造函数,使其提供所需的行为。总之,通过提供一个使用左值引用的构造函数和一个使用右值引用的构造函数,将初始化分成了两组使用左值对象初始化对象时,将使用复制构造函数,而使用右值对象初始化对象时,将使用移动构造函数。程序员可根据需要赋予这些构造函数不同的行为。
这就带来了一个问题:在引入右值引用前,情况是什么样的呢?如果没有移动构造函数,且编译器未能通过优化消除对复制构造函数的需求,结果将如何呢?在C++98中,下面的语句将调用复制构造函数:
Useless four (one +three);
但左值引用不能指向右值。结果将如何呢?第8章介绍过,如果实参为右值,const 引用形参将指向一个临时变量:藺ぜ酋争
int twice(const &rx)(return2*rx;)
...
int main()
int m = 6;//below,rx refers to m
int n= twice(m);//below,rx refers to a temporary variable initialized to 21
int k= twice(21);
首先,在方法Useless::operator+0内,调用构造函数创建了temp,并在01C337C4处给它分配了存储30个元素的空间。然后,调用复制构造函数创建了一个临时复制信息(其地址为01C337E8),f指向该副本。接下来,删除了地址为01C337C4的对象temp。然后,新建了对象fur,它使用了01C337C4处刚释放的内存。接下来,删除了01C337E8处的临时参数对象。这表明,总共创建了三个对象,但其中的两个被删除。这些就是移动语义旨在消除的额外工作。
正如 g++示例表明的,机智的编译器可能自动消除额外的复制工作,但通过使用右值引用,程序员可指出何时该使用移动语义。
18.2.4 赋值
适用于构造函数的移动语义考虑也适用于赋值运算符。例如,下面演示了如何给Uselcss 类编写复制赋值运算符和移动赋值运算符:
Useless & Useless::operator=(const Useless &f)// copy assignment
{
if (this == &f)
return *this;
delete []pc;
n = f.n;
pc =new char[n];
for(int i=0;i <n; i++)
pc[i]= f.pc[i];
return *this;
}
Useless &Useless::operator=(Useless &&f)//move assignment
{
if (this == &f)
return *this;
delete []pc;
n = f.n;
pc=f.pc;
f.n = 0;
f.pc = nullptr;
return *this;
}
上述复制赋值运算符采用了第12章介绍的常规模式,而移动赋值运算符删除目标对象中的原始数据,并将源对象的所有权转让给目标。不能让多个指针指向相同的数据,这很重要,因此上述代码将源对象中的指针设置为空指针。
与移动构造函数一样,移动赋值运算符的参数也不能是const引用,因为这个方法修改了源对象
523

被折叠的 条评论
为什么被折叠?



