big three
拷贝构造函数,拷贝赋值函数,析构函数这三个函数被称为类中的big three。
拷贝构造函数:当我们创建一个对象时,调用构造函数,如果一个对象去初始化同类对象,这个时候就需要使用到拷贝构造函数,目的是将目标对象的成员变量拷贝给另一个对象。
值得注意的是,如果类的成员变量里不涉及指针,我们则不需要显示的声明一个拷贝构造函数,编译器会生成一个默认的拷贝构造函数和析构函数用于对象的拷贝和销毁动作。关于为什么设计指针的类必须要显示声明拷贝构造函数和析沟函数,在下篇说明。
1 Int main(){ 2 Complex a; 3 Complex a(b); 4 Complex a = b; 5 }
拷贝赋值函数:是用于一个对象给另一个对象赋值所用到的函数。
值得注意的是,拷贝构造函数和拷贝赋值函数看起来很类似,但他们其实是有不同的,其内部实现的操作也不同。
我们可以看到,拷贝构造函数的操作是一个对象去初始化另一个对象时所用到的函数,其实这里的另一个对象,里面的数据其实是没有占用真正的内存。在初始化的过程中,将当前对象的值一位一位的拷贝进了另一个对象,所以基于string类拷贝构造的基本操作为:
1.开辟一个相同大小的内存空间
2.逐个字符进行深拷贝
1 inline String::String(const String& str) 2 { 3 m_data = new char[ strlen(str.m_data) + 1 ]; 4 strcpy(m_data, str.m_data); 5 }
而拷贝赋值函数则是将一个对象的值赋给另一个对象,在这里,另一个对象中可能已经存在已经开辟的内存空间的,而不是像拷贝构造函数一样需要拷贝的对象是没有初始化过的。所以与拷贝构造函数的不同点就在于:
1.自我检测赋值,如果遇到obj = obj的情况,不进行自我赋值检测,则直接运行678行代码,将自己的内存释放掉,后续的代码将会出现错误。
2.释放掉原来的内存
3.申请和需拷贝对象大小相同的内存块
4.逐个字符进行深拷贝
5.返回目的对象本身
1 inline String& String::operator=(const String& str) 2 { 3 if (this == &str)//自我赋值检测 4 return *this; 5 6 delete[] m_data;//归还原内存 7 m_data = new char[ strlen(str.m_data) + 1 ];//申请新内存 8 strcpy(m_data, str.m_data);//深度复制内容 9 return *this;//返回对象本身 10 }