拷贝
前提
在对象拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,缺省的拷贝构造函数对于基本类型的成员变量,按字节复制,对于类类型成员变量,调用其相应类型的拷贝构造函数。
阅读《高质量的c c++编程》,第9章有这样一段话,类似的话在《c++primer》《effective C++》都有所提及,那就是拷贝构造函数问题,这个是类编写者的一个基础问题。
位拷贝(浅拷贝)举例,a指向b,b的改变其实会影响a的改变,同时a原本指向的空间发生泄漏。
然后这种情况下有了深拷贝。
我对其绘制思维导图,方便阅读并用分点的方式进行总结;
何时调用?
以下情况都会调用拷贝构造函数:
一个对象以值传递的方式传入函数体
一个对象以值传递的方式从函数返回
一个对象需要通过另外一个对象进行初始化。
浅拷贝:位拷贝,拷贝构造函数,赋值重载
多个对象共用同一块资源,同一块资源释放多次,崩溃或者内存泄漏
深拷贝:每个对象共同拥有自己的资源,必须显式提供拷贝构造函数和赋值运算符。
缺省拷贝构造函数在拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标--浅拷贝。
我们用自己编写的string举例
class String
{
public:
const char* c_str()
{
return _str;
}
String(const char* str = "")
:_str(new char[strlen(str) + 1])
{
strcpy(_str, str);
}
String(const String &s)
:_str(NULL)
{
String tmp(s._str);
swap(_str, tmp._str);
}
~String()
{
if (_str)
{
delete[]_str;
}
}
private:
char* _str;
};
通过开辟空间的方式,进行深拷贝
String s1("字符串1");
String s2(s1);
cout << s2.c_str() << endl;
拷贝成功;
这种方式采取的 拷贝构造,注意这个
String(const String &s)
:_str(NULL)
{
String tmp(s._str);
swap(_str, tmp._str);
}
代码解析:其中this指向拷贝的对象,s指向试图拷贝的原对象。(测试中的 this指向s2,s指向s1)
其中利用构造函数开辟空间,建立临时的tmp,然后进行交换完成拷贝。
当然,我们也可以使用赋值操作符重载完成这一功能(如例子s1=s2)
String& operator =(const String& s)
{
if (this != &s)
{
String tmp(s._str);
swap(tmp._str, _str);
return *this;
}
}//调用构造析构
//本代码是tmp调用的构造函数
String(const char* str = "")
:_str(new char[strlen(str) + 1])
{
strcpy(_str, str);
}
/*String tmp(s._str)
调用这个构造函数,开辟空间,建立一个和s1一样大小的空间,并拷贝值
*/
代码解析:
s1(this),s2(s)
建立tmp,tmp有和s2一样大的空间,一样的数值(调用构造函数),然后交换使s1(this)指向2号空间,获得拷贝,tmp指向3号空间,tmp生命周期结束调用析构函数释放,功能完成。
当然 赋值重载函数可以写的更加简洁
String &operator=(String s)
{
swap(_str, s._str);
return *this;
}
利用tmp的方式是 借助构造函数,这一种方式则是借助拷贝构造函数
相关阅读
开窗函数与聚合函数一样,都是对行的集合组进行聚合计算。它用于为行定义一个窗口(这里的窗口是指运算将要操作的行的集合),它对一组值
这段时间对手机移动应用开发比较感兴趣,借着这个机会就想自己做一个手机应用程序玩玩,还好之前做过关于网页版的手机客户端的开发,就
如何彻底删除手机chrome地址栏的历史记录?手机使用Chrome浏览器进行浏览网页后,都会在浏览器中留下历史记录。在应用中可以对历史记
下载地址:https://download.csdn.net/download/weixin_38895490/10439470点击打开链接pc端配置信息:移动端配置信息压缩包包含目录
实际工作中,一些表格特别是套打时行高列宽经常要求以厘米为单位进行精确设置。而Excel中的行高默认是以磅做单位的,列宽的默认单位