Big Three(拷贝构造,拷贝复制,析构)
class String { public: String (const char* cstr = 0); // 构造函数,默认初值为0 String (const String& str); // 接受的值为类本身,因此为拷贝构造函数 String& operator=(const String& str); // = 号重载,拷贝赋值函数 ~String(); // 析构函数,类死亡时自动调用 char* get_c_str() const { return m_data; } private: char* m_data; } int main() { String s1(); String s2("hello"); String s3(s1); // 拷贝构造,类还未存在 cout << s3 << endl; s3 = s2; // 拷贝赋值,类已经存在 cout << s3 << endl; }
inline String::String(const char* cstr = 0) { if (cstr) { // 指定初值 m_data = new char[strlen(cstr) + 1]; // 分配传进来的长度+ '\0' 的空间 strcpy(m_data, cstr); // 复制 } else { // 未指定初值 m_data = new char[1]; *m_data = '\0'; } } inline String::~String() { delete[] m_data; // 将原来分配的内存释放 }
1. String p1("hello"); //栈中分配内存 2. String p2 = String("hello"); //栈中分配内存,跟方法1相同,是方法1的完整模式 3. String *p3 = new String("hello"); //堆中分配内存
**
方法1、2中都是在栈中分配内存,在栈中内存由系统自动的去分配和释放,释放的顺序也和栈一样,后定义的先释放。
**
**
而使用new创建的指针对象是在堆中分配内存,当不需要该对象时,需要我们手动的去释放,否则会造成内存泄漏。
**
深拷贝,浅拷贝
如果类中有指针成员,则必须写拷贝构造和拷贝赋值函数。
假设 指针a -> "hello", 指针b -> "world",当执行 b = a 时,则变成 b 指向 a,造成 "world" 无人指向,发生了内存泄漏,而"hello" 被 a 和 b 同时指向的情况,那么将来一旦改变 a ,b 也会发生改变。那么,这种拷贝称之为 “浅拷贝”。
深拷贝即为我们自己写的拷贝函数:
inline String::String(const String& str) // 拷贝构造 { m_data = new char[ strlen(str.m_data) + 1 ]; strcpy(m_data, str.m_data); } inline String& String::operator=(const String& str) // 拷贝赋值 { if(this == &str) // 有可能是自己赋值给自己(比如引用),如果不写这句,那么delete就是它自己,下面全错 return *this; delete[] m_data; // 先将自己删除 m_data = new char[ strlen(str.m_data) + 1 ]; // 重新创建和右边一样大的空间 strcpy(m_data, str.m_data); // 重新赋值 return *this; }