C++ 中的拷贝构造函数:浅拷贝、深拷贝

什么时候会调用拷贝构造函数 #

默认拷贝构造函数:浅拷贝 #

即:将被拷贝对象的数据成员的值一一赋值给新创建的对象

实例 #

class Rect{
private:
		int *p;     // 一指针成员
public:
    Rect(){      // 构造函数,p 指向堆中分配的一内存
        p = new int(100); // new 动态分配
    }
    ~Rect(){     // 析构函数,释放动态分配的内存
        if(p != NULL){
            delete p; // delete 释放 p 所指向的内存
        }
    }
};

int main(){
    Rect rect1;
    Rect rect2(rect1);   // 拷贝 rect1 来构造 rect2
		// 也即: Rect rect2 = rect1;
		// 浅拷贝,将成员的值进行拷贝 rect2.p = rect1.p (地址 = 地址)

		// 会出现错误
		// 在 delete 时既要 delete rect2.p 指向的空间,又要 delete rect1.p 指向的内存。但这是同一个内存(地址 = 地址),导致同一个内存被释放两次

    return 0;
}

同时还造成另外两个错误:

自行新建拷贝构造函数:并使用深拷贝 #

新增加一个指针,并申请一个新的内存。新指针指向新内存。

实例 #

class Rect{
public:
    int *p;			// 一指针成员
    Rect(){     // 构造函数,p指向堆中分配的一内存
        p = new int(100);
    }
    Rect(const Rect &r){ // 自行新建拷贝构造函数
        p = new int;     // 为新对象重新动态分配内存
        *p = *r.p;
        // 或带括号 *p = *(r.p);
    }
    ~Rect(){    // 析构函数,释放动态分配的内存
        if(p != NULL){
            delete p;
        }
    }
};

int main(){
    Rect rect1;
    Rect rect2(rect1);		// 拷贝 rect1 来构造 rect2
		// 也即: Rect rect2 = rect1;
    // 深拷贝,创建新的 p 以及其所指向的空间,然后把值赋过去 *r.p = *rect1.p; 然后 *rect2.p = *r.p;

  return 0;
}

不妨输出地址比对一下:

class Rect{
public:
    int *p;
    Rect(){
        p = new int(100);
        cout<<"start new: "<<p<<endl; // 无参的新构造(初始化)时创建的内存空间
    }
    Rect(const Rect &r){
        p = new int;
        cout<<"copy: "<<p<<endl; 			// 拷贝构造时创建的内存空间
        *p = *r.p;
    }
    ~Rect(){
        if(p != NULL){
            cout<<"de: "<<p<<endl; 		// 所析构掉的内存空间
            delete p;
        }
    }
};

int main(){
    Rect rect1;
    cout<<rect1.p<<endl;		// rect1.p 指向的内存空间
    Rect rect2(rect1);			// 拷贝 rect1 来构造 rect2
    cout<<rect2.p<<endl;		// rect2.p 指向的内存空间
    return 0;
}

输出得:

start new: 0x10582d930
0x10582d930
copy: 0x10582f220
0x10582f220
de: 0x10582f220
de: 0x10582d930
Program ended with exit code: 0

参考 #

Webmention this post, or contact me directly.

You can use Hypothes.is to select texts and highlight.

You've copied this page url!

Search it in your Mastodon server, and reply that toot by @fanrongbin.com@fanrongbin.com.