C++--深拷贝与浅拷贝

参考连接:http://c.biancheng.net/view/2336.html

1.深拷贝和浅拷贝怎么理解

深拷贝和浅拷贝是和OOP(object-oriented programming)中类相关的。

深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源 (堆,或者是其它系统资源),当这个类的对象发生复制过程的时候,这个过程就可以叫做深拷贝,反之对象存在资源,但复制过程并未复制资源的情况视为浅拷贝。

最重要的两点:
	深拷贝和浅拷贝:
		是指实例化对象时发生的过程,指的是构造函数要做的事,是通过构造函数实现。
	如下:
	//若Test是个类
	Test t(100);	//实例化对象t,调用有参构造函数
	Test b=t;	//实例化对象b,调用默认无参构造函数
	
	而当两个对象已经实例化出来,如下是个赋值操作,而不是实例化操作
	//若myclass是个类
	myclass a=myclass(1); 
	myclass b=myclass(2); 
	a = b;//赋值操作,操作符 =。

2.浅拷贝

浅拷贝例子,如下:

class Base{
public:
    Base(): m_a(0), m_b(0){ }
    Base(int a, int b): m_a(a), m_b(b){ }
private:
    int m_a;
    int m_b;
};

int main(){
    int a = 10;
    int b = a;  //拷贝 以拷贝的方式初始化的

    Base obj1(10, 20);
    Base obj2 = obj1;  //拷贝 以拷贝的方式初始化的

    return 0;
}

//b 和 obj2 都是以拷贝的方式初始化的。
//具体来说,就是将 a 和 obj1 所在内存中的数据按照二进制位(Bit)复制到 b 和 obj2 所在的内存,这种默认的拷贝行为就是浅拷贝,
//这和调用 memcpy() 函数的效果非常类似。

3.深拷贝

当类持有其它资源时,例如动态分配的内存、指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。
深拷贝例子,如下:

//自定义的 Array 类来实现变长数组。 涉及动态分配内存
#include <iostream>
#include <cstdlib>
using namespace std;

//变长数组类
class Array{
public:
    Array(int len);
    Array(const Array &arr);  //拷贝构造函数
    ~Array();
public:
    int operator[](int i) const { return m_p[i]; }  //获取元素(读取)
    int &operator[](int i){ return m_p[i]; }  //获取元素(写入)
    int length() const { return m_len; }
private:
    int m_len;
    int *m_p;
};

Array::Array(int len): m_len(len){
    m_p = (int*)calloc( len, sizeof(int) );
}

Array::Array(const Array &arr){  //拷贝构造函数
    this->m_len = arr.m_len;
    this->m_p = (int*)calloc( this->m_len, sizeof(int) );
    memcpy( this->m_p, arr.m_p, m_len * sizeof(int) );
}

Array::~Array(){ free(m_p); }

//打印数组元素
void printArray(const Array &arr){
    int len = arr.length();
    for(int i=0; i<len; i++){
        if(i == len-1){
            cout<<arr[i]<<endl;
        }else{
            cout<<arr[i]<<", ";
        }
    }
}

int main(){
    Array arr1(10);
    for(int i=0; i<10; i++){
        arr1[i] = i;
    }
   
    Array arr2 = arr1;
    arr2[5] = 100;
    arr2[3] = 29;
   
    printArray(arr1);
    printArray(arr2);
   
    return 0;
}

//运行结果:
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9
//0, 1, 2, 29, 4, 100, 6, 7, 8, 9
上例显式地定义了拷贝构造函数。
它除了会将原有对象的所有成员变量拷贝给新对象,还会为新对象再分配一块内存,并将原有对象所持有的内存也拷贝过来。
这样做的结果是,`原有对象和新对象所持有的动态内存是相互独立的,更改一个对象的数据不会影响另外一个对象`,
本例中我们更改了 arr2 的数据,就没有影响 arr1。

`这种将对象所持有的其它资源一并拷贝的行为叫做深拷贝,我们必须显式地定义拷贝构造函数才能达到深拷贝的目的`。

使用深拷贝的例子:
	标准模板库(STL)中的 string、vector、stack、set、map 等也都必须使用深拷贝。
	
	
如果希望亲眼目睹不使用深拷贝的后果,可以将上例中的拷贝构造函数删除,那么运行结果将变为:
0, 1, 2, 29, 4, 100, 6, 7, 8, 9
0, 1, 2, 29, 4, 100, 6, 7, 8, 9
可以发现,更改 arr2 的数据也影响到了 arr1。这是因为,在创建 arr2 对象时,默认拷贝构造函数将 arr1.m_p 直接赋值给了 arr2.m_p,导致 arr2.m_p 和 arr1.m_p 指向了同一块内存,所以会相互影响。
posted @ 2023-03-08 09:30  Panor  阅读(64)  评论(0)    收藏  举报