C++中的复制、赋值、析构
一直对C++的复制(Copy)、赋值(Assign)操作比较困惑,现在看书的时候看到了,就把它顺便记下来。
一、什么时候触发
一下代码可以熟悉什么时候触发复制操作,以及什么时候触发赋值操作:
// testCopy.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <string> using namespace std; class testCopy { public: testCopy():a(0) { cout<<"enter constructor"<<endl; }; //重载赋值操作符 testCopy& operator=(const testCopy& t) { cout<<"enter operator="<<endl; a = t.a; return *this; } //复制构造函数 testCopy(const testCopy& t):a(t.a) { cout<<"enter copy constructor"<<endl; } ~testCopy() { cout<<"enter destructor"<<endl; } int a; }; void f1(testCopy t2) { cout<<"enter f1"<<endl; } testCopy f2() { cout<<"enter f2"<<endl; testCopy t3;//调用普通构造函数 return t3;//以类实例为非引用类型返回值时触发复制构造 } int _tmain(int argc, _TCHAR* argv[]) { cout<<"t1"<<endl; testCopy t1;//调用普通构造函数 cout<<"t2"<<endl; testCopy t2(t1);//直接以类实例为参数初始化另一个类实例时触发复制构造 cout<<"t3"<<endl; testCopy t3;//调用普通构造函数 t3 = t1;//将类实例赋值给另一个类实例时触发赋值操作 cout<<"f1"<<endl; f1(t1);//以类实例为非引用类型的参数传递给函数时调用复制构造 cout<<"f2"<<endl; testCopy t4;//调用普通构造函数 t4 = f2();//将类实例赋值给另一个类实例时触发赋值操作 cout<<"end"<<endl; return 0; }
输出结果如下:
t1 enter constructor t2 enter copy constructor t3 enter constructor enter operator= f1 enter copy constructor enter f1 enter destructor f2 enter constructor enter f2 enter constructor enter copy constructor enter destructor enter operator= enter destructor end enter destructor enter destructor enter destructor enter destructor
二、复制、赋值、析构函数重写的必要性
上面的例子不足以说明重写复制、赋值、析构的重要性,当类中需要动态分配内存时,重要性就体现出来了:
class testCopy2 { public: testCopy2():buf(new char[128]) { cout<<"enter constructor"<<endl; }; //重载赋值操作符 testCopy2& operator=(const testCopy2& t) { //如果不重写赋值构造函数,那么多个类实例之间的buf指向的是同一片内存。 cout<<"enter operator="<<endl; memcpy(buf,t.buf,128); return *this; } //复制构造函数 testCopy2(const testCopy2& t):buf(new char[128]) { cout<<"enter copy constructor"<<endl; memcpy(buf,t.buf,128); //如果不重写复制构造函数,那么多个类实例之间的buf指向的是同一片内存。 } ~testCopy2() { //如果不重写析构函数,那么buf指针内存不会被删除。 cout<<"enter destructor"<<endl; delete buf; } char* buf; };
三、一些规则
1. 如果一个类需要一个析构函数,那么它一定需要重载复制和赋值操作。
2. 如果一个类需要重载复制操作,那么它一定需要重载赋值操作,反之同成立。
3. 如果一个类需要重载复制和赋值操作,但是不一定需要重载析构操作。