美文网首页
小心,自定义拷贝函数

小心,自定义拷贝函数

作者: Codeapes | 来源:发表于2019-11-03 15:40 被阅读0次

编译器在生成拷贝函数时只是简单地将原对象的每一个Non-static数据成员拷贝到目标对象中,这就是所说的浅拷贝。这个过程简单粗暴,如果类中有动态配置的内存,对象中包含资源,问题就会随之而产生。

首先,我们需要了解一下浅拷贝与深拷贝可能会产生的问题。

1.浅拷贝

浅拷贝是成员数据之间的一一赋值,又称为Bitwise Copy。

但可能会有这样的情况:如果对象包含资源(堆资源或文件),当进行浅拷贝时,两个资源指针会指向同一资源,就造成两个对象访问同一资源的问题,如下所示:

class Student {
public:

    Student();

    Student(const char* name);

    ~Student();

private:

    char* m_pName;
    int m_nSize;
    
};

Student strSrc("xiaohong");

Student strDst(strSrc);

写出上面这样的代码后,会出现如下情况:

浅拷贝的行为类似于memcpy。于是出现了如下问题:在释放资源的时候会产生资源归属不清的情况,这将导致程序运行出错,这是一个绝对危险的Bug。

2.深拷贝

深拷贝就是用来解决这个问题的,它会把资源也赋值一次,使对象拥有不同的资源,但其资源的内容是一样的。

以堆资源为例,就是再开辟一片堆内存,把原来的内容拷贝过来,如下图所示:

strDst与strSrc中的指针m_pName不再一样,它们分别指向了不同的内存块,但是这两个指针所指向的内存块中的内容却是一样的。

自定义拷贝函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝函数。但是在拒绝编译器默认版本的同时,你也要注意将拷贝类中所有的数据成员拷贝全了。如果你忘记拷贝某一个数据成员,你的代码并不完善,但编译器为了“报复”,是不会告诉你相关情况的,它对此依旧会表示同意。假如我们在为Student自定义拷贝函数时忽略了数据成员m_nSize,代码如下所示:

Student::Student(const Student&rhs) { 

    m_pName = new char[strlen(rhs.m_pName) + 1]; 

    strcpy(m_pName, rhs.m_pName); 
} 

Student&Student::operator=(const Student&rhs) { 

    if(this==&rhs) {

        return *this; 
    }

    if(m_pName != NULL) {

        delete m_pName; 
    }

    m_pName = new char[strlen(rhs.m_pName) + 1]; 

    strcpy(m_pName, rhs.m_pName); 

    return *this; 
}

这种实现方式大部分编译器既不会报错,也不会通过警告提示你忘记拷贝某个数据成员。这种错误一般发生在两个情形之中:

  • 对原有类进行了新设计,添加了新的数据成员,但是没有对该类的拷贝函数做适时的更新。

  • 有继承发生时,忘记对基类部分的数据进行拷贝了。如下所示:

class CollegeStudent : public Student {
public:

    CollegeStudent(const CollegeStudent& rhs)
    :m_nLenOfSchool(rhs.m_nLenOfSchool){}

    CollegeStudent&operator=(const CollegeStudent&rhs) { 

        if(this == &rhs) {

            return *this; 
        }

        m_nLenOfSchool = rhs.m_nLenOfSchool; 

        return *this; 
    }

    ~CollegeStudent(){}

private:

    int m_nLenOfSchool;

}

上述的拷贝函数貌似对所有数据成员都进行了相应的拷贝,但是它却忽略了基类部分。派生类的拷贝函数必须调用对应的基类函数,所以当你打算自己为一个派生类自定义拷贝函数时,必须注意同时拷贝其基类部分。上述CollegeStudent正确的定义方式如下所示:

class CollegeStudent : public Student {
public:

    CollegeStudent(const CollegeStudent& rhs)
    :Student(rhs), m_nLenOfSchool(rhs.m_nLenOfSchool){}

    CollegeStudent&operator=(const CollegeStudent&rhs) { 

        if(this == &rhs) {

            return *this; 
        }

        Student::operator=(rhs);

        m_nLenOfSchool = rhs.m_nLenOfSchool; 

        return *this; 
    }

    ~CollegeStudent(){}

private:

    int m_nLenOfSchool;

}

3.总结

所以,如果类中具有动态配置的内存,我们需要自行实现拷贝函数。在自定义拷贝函数时,应保证拷贝一个对象的All Parts(所有数据成员、基类部分、指针成员所指向的资源)。


个人主页:

www.codeapes.cn

相关文章

  • 小心,自定义拷贝函数

    编译器在生成拷贝函数时只是简单地将原对象的每一个Non-static数据成员拷贝到目标对象中,这就是所说的浅拷贝。...

  • [C++之旅] 12 拷贝构造函数

    [C++之旅] 12 拷贝构造函数 拷贝构造函数的特点 如果没有自定义的拷贝构造函数则系统自动生成一个默认的拷贝构...

  • 【GeekBand】class with pointer mem

    1.拷贝构造函数 如果没有自定义拷贝构造函数,则编译器默认构造一个,直接按位拷贝。 类中如果带指针则一定要自己...

  • C++语言基础(02)

    1.可变参数 2.构造函数、析构函数、拷贝构造函数 构造函数 拷贝构造函数 //浅拷贝(值拷贝)问题 //深拷贝

  • (GeekBand)Second class

    一、Big Three:拷贝构造函数,拷贝赋值函数,析构函数 1.拷贝构造函数 文字定义:拷贝构造函数,又称复制构...

  • C++面向对象高级编程(上)-第二周-博览网

    第二周 三大函数:拷贝构造,拷贝赋值,析构 字符串的构造函数,拷贝构造函数, 拷贝构造函数和拷贝赋值函数没有自主定...

  • C++类的默认函数解析、浅拷贝、深拷贝

    拷贝构造函数 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。...

  • c++:拷贝构造函数&&深浅拷贝

    默认拷贝构造函数的汇编代码: 其实就相当于这一段代码 拷贝构造函数 多态拷贝构造函数 子类拷贝构造函数调用父类拷贝...

  • C++boolan part1_week2

    Big Three三个特殊函数 (拷贝构造函数、拷贝赋值函数、析构函数) 1 拷贝构造函数 定义:如果一个构造函数...

  • [GeekBand]第二周学习笔记

    三大函数:拷贝构造,拷贝赋值,析构 任何带有pointer members的类必须有拷贝构造函数和拷贝赋值函数。 ...

网友评论

      本文标题:小心,自定义拷贝函数

      本文链接:https://www.haomeiwen.com/subject/wbtlbctx.html