文章目录
- what is 移动构造函数?
- 移动构造函数的实现的例子
- when 移动构造函数?
- 在C++98之前,没有移动构造函数,是怎么做的呢?
- 后记
what is 移动构造函数?
构造函数string(string&& str)类似于复制构造函数,导致新创建的 string为 str 的副本。但与复制构造函数不同的是,它不保证将 str视为const,可修改源对象,还可能转让所有权而不做任何复制(对比来看,复制构造函数完整的保留源对象)。这种构造函数被称为移动构造函数(move constructor)。如果源对象是临时的,移动操作的效率将高于常规复制。
(总结自《C++ primer plus》)
移动构造函数的实现的例子
解释一下成员变量
ct是静态成员,统计出对象数量。pc是point to data,值是new出来的一个数组的指针。n是数组元素的个数。
然后解释这个移动构造函数:
-
n(f.n)是参数表,意思等同于this.n = f.n
-
大括号之内的第一行,ct自增。因为稍后对原件进行析构时,ct还会自减。为了达到“仅移交对pc指向的数组的控制权,而其余量不变”的效果,故先自增。
-
第二行,this.pc = f.pc移交控制权。
如果,到此为止结束,那么就是编译器默认造出来的复制构造函数干的活儿。此时,pe 和fpe 指向相同的数据,调用析构函
数时这将带来麻烦,因为程序不能对同一个地址调用delete[]两次。 -
第三行,把原来的变量的成员都窃取之后,原pc被置为空指针,因为稍后对原件进行析构,delete[]一个空指针nullptr,是没有问题的。
-
第四行可以不写。
when 移动构造函数?
要让移动语义发生,需要两个步骤。①右值引用让编译器知道何时可使用移动语义,②编写移动构造函数,使其提供所需的行为。
Complex c(a + b);
上例,这里函数a+b的返回值就是右值。(为何常规函数返回值是右值呢?这是因为这种返回值位于临时内存单元中,运行到下一条语句时,它们可能不再存在。)
vector<int> fun(void)
{
vector<int> nums;
// ……在此,nums中存入一些数据……
return nums;
}
对于上例,待返回值也是右值吗?以下是一个测试:
在C++98之前,没有移动构造函数,是怎么做的呢?
如果没有移动构造函数,那就用的是复制构造函数:
后记
研究这个问题的起因是,不理解为什么在一个函数内部声明的vector容器可作为返回值而不出错?潜意识里,vector作为局部变量,被调函数返回后vector会被析构的,那再在主调函数中访问vector中的元素,怎么就能访问呢?
// 就是这个例子
vector<int> fun(void)
{
vector<int> nums;
// ……在此,nums中存入一些数据……
return nums;
}
通过研究,我的结论是,无论是新特性的移动构造函数,还是原来的复制构造函数,stl的vector内部实现都是深拷贝。stl内部可能的实现方式,可能是移交控制权+析构空指针,也可能是逐个元素去复制+析构局部变量的那个vector。总之,由于其良好的内部实现,不会发生错误。换言之,局部申请的vector可以直接作为返回值。