C++中的浅拷贝和深拷贝
目录
1.string类的模拟实现
1.1经典的string类问题
1.2浅拷贝
1.3深拷贝
1.3.1传统版本写法的String类
1.3.2现代版写法的String类
1.3写时拷贝(了解)
2.扩展阅读:
【揭秘!】这里有你从未听过的独特见解,快来点赞关注,开启智慧之旅
1. 经典的string类问题
//为了和标准库区分,此处使用String
class String
{
public:/*String():_str(new char[1]){*_str = '\0'}*///String(const char* str = '\0') 错误示范//String(const char* str = nullptr)错误示范String(const char* str = ""){//构造String类对象时,如果传递nullptr指针,可以认定程序非法if(ptr == nullptr){assert(false);return ;}_str = new char[strlen(str) + 1];strcpy(_str,str);}~String(){if(_str){delete[] _str;_str = nullptr;}}
private:char* _str;
};//测试
void TsstString()
{String s1("hello cx");String s2(s1);
}
说明:上述String类没有显示定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当是s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式称为浅拷贝。
2. 浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以继续对资源进行操作时,就会发生访问违规。
就像一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一起玩,则万事大吉,万一不想分享就你争我夺,玩具损坏。
可以采用深拷贝解决浅拷贝的问题,即:每个对象都有一份独立的资源,不要和其他对象共享。
父亲给每给每个孩子都买一份玩具,各自玩各自的就不会有问题了。
3. 深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显示给出。一般情况都是按照深拷贝方式提供。
3.1 传统版本写法的String类
class String
{
public:String(const char* str =""){//构造String类对象时,如果传递nullptr指针,可以认为程序非法if(nullptr == str){assert(false);return ;}_str = new char[strlen(str)+1];strcpy(_str,str);}String(const String& s): _str(new char[strlen(s._str)+1]{strcpy(_str,s._str);}String& operator=(const String& s){if(this != &s){char* pStr = new char[strlen(s._str)+1];strcpy(pStr,s._str);delete[] _str;_str = pStr; }return *this;}~String(){if(_str){delete[] _str;_str = nullptr;}}private:char* _str;
};
3.2 现代版写法的String类
class String
{
public:String(const char* str = "") {if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s):_str(nullptr){String strTmp(s._str);swap(_str, strTmp._str);}//对比下面和上面的赋值哪个实现比较好String& operator=(String s){swap(_str, s._str);return *this;}//String& operator=(const String& s)//{// if (this != &s)// {// String strTmp(s);// swap(_str, strTmp._str);// }// return *this;//}~String(){if (_str){delete[] _str;_str = nullptr;}}private:char* _str;
};
4. 写时拷贝(了解)
写时拷贝就是一种拖延,是在浅拷贝的基础上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个。在构造时,将资源的技计数给成1,每增加一个对象使用该资源时,就给计数增加1,当某个对象销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象是资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。
写时拷贝
写时拷贝在读取时的缺陷
5. 扩展阅读:
面试中string的一种正确写法
STL中的string类怎么了
用心呈现,只为遇见更好的你!点赞关注,让我们的博客陪伴你成长!