C++11:移动构造函数【写法+调用时机】【C++返回vector为什么不报错】

文章目录

      • what is 移动构造函数?
      • 移动构造函数的实现的例子
      • when 移动构造函数?
      • 在C++98之前,没有移动构造函数,是怎么做的呢?
      • 后记

what is 移动构造函数?

构造函数string(string&& str)类似于复制构造函数,导致新创建的 string为 str 的副本。但与复制构造函数不同的是,它不保证将 str视为const,可修改源对象,还可能转让所有权而不做任何复制(对比来看,复制构造函数完整的保留源对象)。这种构造函数被称为移动构造函数(move constructor)。如果源对象是临时的,移动操作的效率将高于常规复制。

(总结自《C++ primer plus》)

移动构造函数的实现的例子

C++11:移动构造函数【写法+调用时机】【C++返回vector为什么不报错】_第1张图片

解释一下成员变量

ct是静态成员,统计出对象数量。pc是point to data,值是new出来的一个数组的指针。n是数组元素的个数。

然后解释这个移动构造函数:

  1. n(f.n)是参数表,意思等同于this.n = f.n

  2. 大括号之内的第一行,ct自增。因为稍后对原件进行析构时,ct还会自减。为了达到“仅移交对pc指向的数组的控制权,而其余量不变”的效果,故先自增。

  3. 第二行,this.pc = f.pc移交控制权。
    如果,到此为止结束,那么就是编译器默认造出来的复制构造函数干的活儿。此时,pe 和fpe 指向相同的数据,调用析构函
    数时这将带来麻烦,因为程序不能对同一个地址调用delete[]两次。

  4. 第三行,把原来的变量的成员都窃取之后,原pc被置为空指针,因为稍后对原件进行析构,delete[]一个空指针nullptr,是没有问题的。

  5. 第四行可以不写。

when 移动构造函数?

要让移动语义发生,需要两个步骤。①右值引用让编译器知道何时可使用移动语义,②编写移动构造函数,使其提供所需的行为。

Complex c(a + b);

上例,这里函数a+b的返回值就是右值。(为何常规函数返回值是右值呢?这是因为这种返回值位于临时内存单元中,运行到下一条语句时,它们可能不再存在。)

vector<int> fun(void)
{
    vector<int> nums;
    // ……在此,nums中存入一些数据……
    return nums;
}

对于上例,待返回值也是右值吗?以下是一个测试:
C++11:移动构造函数【写法+调用时机】【C++返回vector为什么不报错】_第2张图片

在C++98之前,没有移动构造函数,是怎么做的呢?

如果没有移动构造函数,那就用的是复制构造函数:
C++11:移动构造函数【写法+调用时机】【C++返回vector为什么不报错】_第3张图片

后记

研究这个问题的起因是,不理解为什么在一个函数内部声明的vector容器可作为返回值而不出错?潜意识里,vector作为局部变量,被调函数返回后vector会被析构的,那再在主调函数中访问vector中的元素,怎么就能访问呢?

// 就是这个例子
vector<int> fun(void)
{
    vector<int> nums;
    // ……在此,nums中存入一些数据……
    return nums;
}

通过研究,我的结论是,无论是新特性的移动构造函数,还是原来的复制构造函数,stl的vector内部实现都是深拷贝。stl内部可能的实现方式,可能是移交控制权+析构空指针,也可能是逐个元素去复制+析构局部变量的那个vector。总之,由于其良好的内部实现,不会发生错误。换言之,局部申请的vector可以直接作为返回值。

你可能感兴趣的:(C/C++/C#基础,c++,开发语言)