C++中的移动构造函数及move语句示例详解

2020-01-06 17:28:49王旭

输出结果为:

C++,move构造函数,c,移动构造函数,move,构造函数

首先结果并不符合预期,我们希望b对象中的字符串也是I love BIT但是输出为空,这是因为b->value和a->value指向了同一片内存区域,当delete a的时候,该内存区域已经被收回,所以再用b->value访问那块内存实际上是不合适的,而且,虽然我运行时程序没有崩溃,但是程序存在崩溃的风险呀,因为当delete b的时候,那块内存区域又被释放了一次,两次释放同一块内存,相当危险呀。

我们用valgrind检查一下,发现,相当多的内存错误呀!

C++,move构造函数,c,移动构造函数,move,构造函数

其中就有一个Invalid free 也就是删除b的时候调用析构函数,对已经释放掉对空间又释放了一次。

那么深层复制应该怎样写呢?

代码如下:


#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>

using namespace std;

class Str{
 public:
 char *value;
 Str(char s[])
 {
 cout<<"调用构造函数..."<<endl;
 int len = strlen(s);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,s);
 }
 Str(Str &v)
 {
 cout<<"调用拷贝构造函数..."<<endl;
 int len = strlen(v.value);
 value = new char[len + 1];
 memset(value,0,len + 1);
 strcpy(value,v.value);
 }
 ~Str()
 {
 cout<<"调用析构函数..."<<endl;
 if(value != NULL)
 {
  delete[] value;
  value = NULL;
 }
 }
};

int main()
{

 char s[] = "I love BIT";
 Str *a = new Str(s);
 Str *b = new Str(*a);
 delete a;
 cout<<"b对象中的字符串为:"<<b->value<<endl;
 delete b;
 return 0;
}

结果为:

C++,move构造函数,c,移动构造函数,move,构造函数

这次达到了我们预想的效果,而且,用valgrind检测一下,发现,没有内存错误!

C++,move构造函数,c,移动构造函数,move,构造函数

所以,写拷贝构造函数的时候,切记要注意指针的浅层复制问题呀! 

好的,回顾了一下拷贝构造函数,下面回到移动构造函数上来。

有时候我们会遇到这样一种情况,我们用对象a初始化对象b,后对象a我们就不在使用了,但是对象a的空间还在呀(在析构之前),既然拷贝构造函数,实际上就是把a对象的内容复制一份到b中,那么为什么我们不能直接使用a的空间呢?这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷。