打赏

[C++] 深拷贝和浅拷贝

c++的类中含有指针类型时,在进行拷贝时要注意深拷贝和浅拷贝的问题。

(1) 浅拷贝采用"位拷贝"的方式。对于基础类型,如int, float等,可以直接copy过来;

但是对于指针类型,在copy时要格外注意,浅拷贝只copy了指针指向的地址,并未复制创建该地址上的对象内容,容易引发内存泄露、多次析构等问题。

(2) 深拷贝则为新对象的成员重新开辟内存空间,每个对象共同拥有自己的资源,必须显式提供拷贝构造函数和赋值运算符。

1. 浅拷贝的问题

以类File为例,首先创建了File类型的一个对象a, File类型的对象b是由a 浅拷贝得到。

在浅拷贝时,对于a中的指针类型对象_fp,b只copy了a中_fp指针指向的对象的地址

那么浅拷贝后,a, b对象的_fp指针都指向了同一块内存

这在类进行析构时很容易出现被多次析构的问题。 

#include <iostream>
using namespace std;

class File
{
public:
    explicit File(const char *file_name) {};
    ~File() {};

    void addr_fp() {
        cout << _fp << endl;
    }

private:
    FILE *_fp; 
};

int main()
{
    File a("./a.txt");
    cout << "a._fp addr" << endl;
    a.addr_fp();

    File b = a;
    cout << "b._fp addr" << endl;
    b.addr_fp();

    return 0;
}

/** output

a._fp addr
0x7ffee45649d8
b._fp addr
0x7ffee45649d8

**/

 

2. 解决方法

对于含有指针类型的类,可以采用进制拷贝构造、赋值构造等方式来避免(1)中的问题。(RAII没有复制行为)

下例中通过定义一个拷贝和赋值构造的宏,并在private中进行声明,

那么如果有企图对该类对象进行拷贝或赋值构造,会触发private 的constructor引发报错。

#include <iostream>
using namespace std;

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
        TypeName(const TypeName&);\
        TypeName& operator=(const TypeName&) 


class File
{
public:
    explicit File(const char *file_name) {};
    ~File() {};

    void addr_fp() {
        cout << _fp << endl;
    }

private:
    FILE *_fp; 
    DISALLOW_COPY_AND_ASSIGN(File);
};

int main()
{
    File a("./a.txt");
    cout << "a._fp addr" << endl;
    a.addr_fp();

    File b = a;
    cout << "b._fp addr" << endl;
    b.addr_fp();

    return 0;
}


/** output

deep_shallow_copy.cpp:30:11: error: calling a private constructor of class 'File'
        File b = a;
                 ^
deep_shallow_copy.cpp:21:27: note: declared private here
        DISALLOW_COPY_AND_ASSIGN(File);
                                 ^
1 error generated.

**/

 

posted @ 2020-08-16 23:00  listenviolet  阅读(501)  评论(0编辑  收藏  举报