C++的深浅拷贝和写时拷贝你了解吗

目录
  • 1.浅拷贝
  • 2.深拷贝
  • 3.引用计数+写时拷贝
  • 总结

1.浅拷贝

浅拷贝:对于有申请空间的对象的类来说,是按照字节序依次拷贝过去的,并没有另外申请一块空间。因此,在调用析构函数的时候会造成同一块空间释放两次的情况,从而使程序崩溃。

如下实例:

class string
{
public:
	string(const char* str)
	{
		//构造string类对象时,如果传递nullptr指针
		//认为程序非法,此处断言下
		assert(str);
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	~string()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};
void test()
{
	string s1("linmanman");
	string s2(s1);
}

运行看看,报错了

分析错因:

浅拷贝是指向同一块空间的,这样就会有俩个无法避免的问题:

1.析构俩次空间,程序崩溃

2.其中一个的值被修改了,会影响到另外一个的值。

深拷贝:给每个对象单独分配资源,就是给待拷贝的对象另开一片空间,再把原对象空间上的值拷贝过来,这样在调用析构函数的时候就不会产生冲突。

2.深拷贝

传统写法的string类的深拷贝是自己开空间,自己将拷贝的对象拷贝到待拷贝对象中。

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类的深拷贝堪称是“移花接木”

string(const string& s)
	:_str(nullptr)//必须置空,因为_str开始是个随机数,交换给tmp._str后,释放会引起问题
{
	string tmp(s._str);//直接利用构造函数,给tmp对象开辟了一块空间
	swap(tmp);
}
string& operator=(string s)
{
	swap(s);//这个swap是咱们自己写的哦
	return *this;
}

顺带提一嘴,各个编译器深拷贝的底层实现略有差异(当然逻辑是一样的)

VS 2013下的深拷贝

g++下的深拷贝

3.引用计数+写时拷贝

写时拷贝就是一种拖延症, 是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者, 将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 带你粗略了解C++中的深浅拷贝

    目录 一. 背景 二. 代码实现 三. 问题 四. 解决方法 总结 一. 背景 首先看这样一个问题,在Car类中聚合了Engine类 二. 代码实现 下面给出类Car与类Engine的定义 Car.h #ifndef COPY__CAR_H_ #define COPY__CAR_H_ #include "Engine.h" #include <string> using namespace std; class Car { public: // 构造函数 Car(); Ca

  • C++写时拷贝实现原理及实例解析

    一.什么是写时拷贝 写入时复制是一种计算机程序设计领域的优化策略.其核心思想是,如果有多个调用者同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变. 这个过程对其他的调用者是透明的(transparently). 此作法的主要优点是如果调用者没有修改该资源,就不会有副本被建立,因此多个调用者只是读取操作是可以共享同一

  • C++深浅拷贝和string类的两种写法详解

    目录 一.深浅拷贝 二.string类的两种写法 1.传统写法 2.现代写法 总结 一.深浅拷贝 拷贝这个词对于我们来说应该不陌生,比如我们平常的复制和粘贴就是拷贝:但是如果把拷贝这个词放到C++中来说就有一些复杂了,我们先来看一下什么是浅拷贝: 下面用字符串类来模拟实现. class Astring { public: //构造函数 Astring(const char* str = "") { _str = new char[strlen(str) + 1]; strcpy(_st

  • c++中深浅拷贝以及写时拷贝的实现示例代码

    本文主要给大家介绍了关于c++中深浅拷贝及写时拷贝实现的相关内容,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 一:浅拷贝&深拷贝 浅拷贝:在拷贝构造的时候,直接将原内容的地址交给要拷贝的类,两个类共同指向一片空间.但是存在很大的缺陷:①一旦对s2进行操作,s1的内容也会改变:②析构时先析构s2,再析构s1,但是由于s1,s2指向同一片空间,会导致一片空间的二次析构导致出错. 深拷贝:通过开辟和源空间大小相同的空间并将内容拷贝下来再进行操作.不论是否对s2进行操作,都会拷贝一片相

  • C++深浅拷贝和写时拷贝图文详解

    前言 之前我们在浅谈6个成员函数中有提到深浅拷贝的问题,现在再回首掏一把. 一.深浅拷贝哪家强? 先给出代码理一理 #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include<assert.h> using namespace std; class String { friend ostream& operator<<(ostream &out, const String &s);

  • 深入理解C/C++中的写时拷贝

    写时拷贝 何为写时拷贝? 前面我说过深拷贝浅拷贝,今天我们来探究一下写时拷贝.深拷贝是补充了浅拷贝的不足,写时拷贝其实也就是补充一点深拷贝的不足.其实写时拷贝的意思就是: 当你读取到这个空间的时候,并不会开辟出一个一模一样的空间出来给你,当你真正需要拷贝的时候,那么他就会开辟出空间给你.也就是拖延版的深拷贝. 写时拷贝技术是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(

  • C++的深浅拷贝和写时拷贝你了解吗

    目录 1.浅拷贝 2.深拷贝 3.引用计数+写时拷贝 总结 1.浅拷贝 浅拷贝:对于有申请空间的对象的类来说,是按照字节序依次拷贝过去的,并没有另外申请一块空间.因此,在调用析构函数的时候会造成同一块空间释放两次的情况,从而使程序崩溃. 如下实例: class string { public: string(const char* str) { //构造string类对象时,如果传递nullptr指针 //认为程序非法,此处断言下 assert(str); _str = new char[str

  • 详谈Linux写时拷贝技术(copy-on-write)必看篇

    COW技术初窥 在linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了"写时复制"技术,也就是只有进程空间的各段的内容要发生变化时,才将父进程的内容复制一份给子进程. 那么子进程的物理空间没有代码,怎么去取指令执行exec系统调用呢?? 在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段.数据段.堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,其对应的物理空间是一

  • String类的写时拷贝实例

    实例如下: #include<iostream> using namespace std; class String; ostream& operator<<(ostream &out, const String&s); //引用计数器类 class String_rep { friend class String; friend ostream& operator<<(ostream &out, const String&

  • PHP 之 写时复制介绍(Copy On Write)

    在开始之前,我们可以先看一段简单的代码: 复制代码 代码如下: <?php   //例一     $foo = 1;     $bar = $foo;     echo $foo + $bar; ?> 执行这段代码,会打印出数字2.从内存的角度来分析一下这段代码"可能"是这样执行的:分配一块内存给foo变量,里面存储一个1: 再分配一块内存给bar变量,也存一个1,最后计算出结果输出.事实上,我们发现foo和bar变量因为值相同,完全可以使用同一块内存,这样,内存的使用就节

  • Linux中拷贝 cp命令中拷贝所有的写法详解

    今天在编写一个脚本的时候,发现一个比较奇怪的问题:就是在使用cp拷贝当前目录下所有文件到目标目录的时候,源和目标目录大小不同.原来一直没有留意有这样的问题,后来查了些资料,才知道以前一直使用的格式有误, 一.预备 cp就是拷贝,最简单的使用方式就是: cp oldfile newfile 但这样只能拷贝文件,不能拷贝目录,所以通常用: cp -r old/ new/ 那就会把old目录整个拷贝到new目录下.注意,不是把old目录里面的文件拷贝到new目录,而是把old直接拷贝到new下面,结果

  • PHP中copy on write写时复制机制介绍

    什么是写时复制(Copy On Write)? 答:在复制一个对象的时候并不是真正的把原先的对象复制到内存的另外一个位置上,而是在新对象的内存映射表中设置一个指针,指向源对象的位置,并把那块内存的Copy-On-Write位设置为1.这样,在对新的对象执行读操作的时候,内存数据不发生任何变动,直接执行读操作:而在对新的对象执行写操作时,将真正的对象复制到新的内存地址中,并修改新对象的内存映射表指向这个新的位置,并在新的内存位置上执行写操作. 这个技术需要跟虚拟内存和分页同时使用,好处就是在执行复

随机推荐