注意指针类型成员变量的深拷贝问题
拷贝构造属于定义,并赋值
拷贝赋值属于已经定义,只是赋值。
拷贝构造的深拷贝,因为如果提供了拷贝构造函数,则构造该对象时使用的是拷贝构造函数。
在拷贝构造函数中只需要:
分配新资源,拷贝新内容,返回自引用即可。
但是在拷贝赋值函数中,如果存在指针成员变量一般在对象定义时已经调用构造函数分配了内存。
拷贝赋值时,需要释放旧资源,即释放在定义时调用的构造函数分配的内存,在拷贝赋值函数中重新分配内存。
另外,避免自赋值,主要是在赋值时传递的对象自身,赋值源如果在释放旧资源时被释放,拷贝新内容的内容就是不存在的。
拷贝赋值注意:
1.避免自赋值;
2.分配新资源;
3.释放旧资源;
4.拷贝新内容;
5.返回自引用;
#include <iostream> using namespace std; class Integer { public: Integer (int i) : m_i (new int (i)) {} /* 缺省的支持浅拷贝的拷贝构造函数 Integer (Integer const& that) : m_i (that.m_i) {} */ // 自定义支持深拷贝的拷贝构造函数 Integer (Integer const& that) : m_i (new int (*that.m_i)) {} ~Integer (void) { if (m_i) { delete m_i; m_i = NULL; } } /* 缺省的支持浅拷贝的拷贝赋值运算符函数 Integer& operator= (Integer const& rhs) { cout << "拷贝赋值运算符函数" << endl; m_i = rhs.m_i; } */ // 自定义支持深拷贝的拷贝赋值运算符函数 Integer& operator= (Integer const& rhs) { if (&rhs != this) { // 防止自赋值 int* i = new int (*rhs.m_i); delete m_i; // 释放旧资源 m_i = i; // 分配新资源 // 拷贝新内容 } return *this; // 返回自引用 } int* m_i; };
支持深拷贝的拷贝构造和拷贝赋值类示例:
#include <cstring> #include <iostream> using namespace std; class String { public: String (char const* str = NULL) : m_str (strcpy ( new char [strlen (str ? str : "") + 1], str ? str : "")) {} String (String const& that) : m_str (strcpy ( new char [strlen (that.m_str) + 1], that.m_str)) {} ~String (void) { if (m_str) { delete[] m_str; m_str = NULL; } } // 老鸟 String& operator= (String const& rhs) { if (&rhs != this) { //防止自赋值 String str (rhs); //复用构造函数创建一个对象,并将构造出的对象 //经过swap函数将里面的指针指向与当前对象里面的指针指向交换后在将当前对象返回。 swap (m_str, str.m_str);//交换指针指向 } return *this; } char const* c_str (void) const { return m_str; } private: char* m_str; }; int main (void) { String s1 ("hello"); cout << s1.c_str () << endl; String s2 = s1; cout << s2.c_str () << endl; String s3 ("world"); s2 = s3; cout << s2.c_str () << endl; return 0; }