String类的浅拷贝、深拷贝、引用计数、写时拷贝

2024-04-25 12:32

本文主要是介绍String类的浅拷贝、深拷贝、引用计数、写时拷贝,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

皆以s2=s1为例

浅拷贝:只是直接将s1的值拷贝过来,s1、s2共用同一块内存。

class String
{
public:String(const char* str):_str(new char[strlen(str) + 1]){strcpy(_str, str);}String(const String& s):_str(s._str){}String& operator=(const String& s){if (this != &s){_str = s._str;}return *this;}~String(){if (_str){cout << "delete" << endl;delete[] _str;}}private:char* _str;
};void TestString()
{String s1("bigbang");String s2(s1);String s3("12345");s3 = s1;
}
int main()
{TestString();system("pause");return 0;
}
缺陷是调用析构函数时一块内存会被多次释放,导致程序崩溃。


深拷贝:在拷贝构造时开辟了空间,s1、s2各占有一块内存,无论析构多少次程序都不会崩溃。

//深拷贝传统写法
class String
{
public:String(char* str = ""):_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)  //缺陷:new开辟空间可能会失败,s1将会被破坏//{//	if (this != &s)//	{//		delete[] _str;//		_str = new char[strlen(s._str) + 1];//		strcpy(_str, s._str);//	}//	return *this;//}String& operator=(const String& s)  //解决了上述缺陷{if (this != &s){char* tmp = new char[strlen(s._str) + 1];strcpy(tmp, s._str);delete[] _str;_str = tmp;}return *this;}~String(){if (_str){cout << "delete" << endl;delete[] _str;_str = NULL;}}
private:char* _str;
};void TestString()
{String s1("bigbang");String s2(s1);
}
int main()
{TestString();system("pause");return 0;
}

//深拷贝现代写法:只在构造函数中new,只在析构函数中delete,可维护性变强
class String
{
public:String(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& operator=(const String& s){if (_str != s._str){String tmp(s);swap(_str, tmp._str);}return *this;}//String& operator=(String s) //针对已经存在的两个对象//{//	swap(_str, s._str);//	return *this;//}~String(){if (_str){cout << "delete" << endl;delete[] _str;_str = NULL;}}private:char* _str;
};void TestString()
{String s1("bigbang");  String s2(s1);String s3;s3 = s1;
}
int main()
{TestString();system("pause");return 0;
}

在引用计数中,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。

class String
{
public:String(char* str = ""):_str(new char[strlen(str) + 1]), _refCount(new int(1)){strcpy(_str, str);}String(const String& s):_str(s._str), _refCount(s._refCount){++(*_refCount);}String& operator=(const String& s){// 1.s1和s2是否指向同一块空间// 2.减减s1指向空间的引用计数,如s1是最后一块管理对象,则释放if (_str != s._str){this->Release();_str = s._str;_refCount = s._refCount;++(*_refCount);}return *this;}String& operator=(String s)  //s是临时开辟出来的一块空间,出了函数会自动释放{swap(_str, s._str);swap(_refCount, s._refCount);  //交换后引用计数不改变return *this;}~String(){Release();}void Release(){if (--(*_refCount) == 0){cout << "delete" << endl;delete[] _str;delete _refCount;  //注意delete的格式和new的格式对齐}}
private:char* _str;int* _refCount;
};void TestString()
{String s1("bigbang");String s2(s1);String s3;s3 = s1;
}
int main()
{TestString();system("pause");return 0;
}

//引用计数的浅拷贝--现代写法+写时拷贝:指用浅拷贝的方法拷贝其他对象,多个指针指向同一块空间,
//只有当对其中一个对象修改时,才会开辟一个新的空间给这个对象,和它原来指向同一空间的对象不会受到影响。
class String
{
public:String(char* str = ""):_str(new char[strlen(str) + 1]), _refCount(new int(1)){strcpy(_str, str);}String(const String& s):_str(s._str), _refCount(s._refCount){++(*_refCount);}String& operator=(const String& s){if (_str != s._str){this->Release();_str = s._str;_refCount = s._refCount;++(*_refCount);}return *this;}String& operator=(String s){swap(_str, s._str);swap(_refCount, s._refCount);return *this;}void Release(){if (--(*_refCount) == 0){cout << "delete" << endl;delete[] _str;delete _refCount;}}~String(){Release();}char& operator[](size_t index){CopyOnWrite();assert(index < strlen(_str));return _str[index];}const char& operator[](size_t index) const{assert(index < strlen(_str));return _str[index];}void CopyOnWrite(){if (*_refCount > 1){char* tmp = new char[strlen(_str) + 1];strcpy(tmp, _str);--(*_refCount);_refCount = new int(1);_str = tmp;}}private:char* _str;int* _refCount;
};void Fun(const String& s)
{cout << s[4] << endl;
}
void TestString()
{String s1("bigbeng");String s2(s1);String s3 = s2;Fun(s1);s1[4] = 'a';cout << s1[4] << endl;
}
int main()
{TestString();system("pause");return 0;
}





这篇关于String类的浅拷贝、深拷贝、引用计数、写时拷贝的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/934688

相关文章

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

JavaSE(十三)——函数式编程(Lambda表达式、方法引用、Stream流)

函数式编程 函数式编程 是 Java 8 引入的一个重要特性,它允许开发者以函数作为一等公民(first-class citizens)的方式编程,即函数可以作为参数传递给其他函数,也可以作为返回值。 这极大地提高了代码的可读性、可维护性和复用性。函数式编程的核心概念包括高阶函数、Lambda 表达式、函数式接口、流(Streams)和 Optional 类等。 函数式编程的核心是Lambda

17 通过ref代替DOM用来获取元素和组件的引用

重点 ref :官网给出的解释是: ref: 用于注册对元素或子组件的引用。引用将在父组件的$refs 对象下注册。如果在普通DOM元素上使用,则引用将是该元素;如果在子组件上使用,则引用将是组件实例: <!-- vm.$refs.p will be the DOM node --><p ref="p">hello</p><!-- vm.$refs.child will be the c

YOLOv8/v10+DeepSORT多目标车辆跟踪(车辆检测/跟踪/车辆计数/测速/禁停区域/绘制进出线/绘制禁停区域/车道车辆统计)

01:YOLOv8 + DeepSort 车辆跟踪 该项目利用YOLOv8作为目标检测模型,DeepSort用于多目标跟踪。YOLOv8负责从视频帧中检测出车辆的位置,而DeepSort则负责关联这些检测结果,从而实现车辆的持续跟踪。这种组合使得系统能够在视频流中准确地识别并跟随特定车辆。 02:YOLOv8 + DeepSort 车辆跟踪 + 任意绘制进出线 在此基础上增加了用户

Linux 使用rsync拷贝文件

显示进度条 rsync 可以显示进度条,您可以使用 --progress 或 -P 选项来显示每个文件的传输进度和已完成文件的统计信息。 显示进度条的常用选项: --progress 选项 使用 --progress 显示每个文件的传输进度信息:rsync -av --progress /src/ /dest/ -a:归档模式,表示递归拷贝并保持文件权限、时间戳等。-v:详细模式,显示更

python基础语法十一-赋值、浅拷贝、深拷贝

书接上回: python基础语法一-基本数据类型 python基础语法二-多维数据类型 python基础语法三-类 python基础语法四-数据可视化 python基础语法五-函数 python基础语法六-正则匹配 python基础语法七-openpyxl操作Excel python基础语法八-异常 python基础语法九-多进程和多线程 python基础语法十-文件和目录操作

插件maven-search:Maven导入依赖时,使用插件maven-search拷贝需要的依赖的GAV

然后粘贴: <dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>8.0.26</version> </dependency>

归并排序/计数排序

1:归并排序 1.1:代码 void _MergeSort(int* arr, int left, int right, int* tmp){if (left >= right){return;}int mid = (left + right) / 2; _MergeSort(arr, left, mid, tmp); _MergeSort(arr, mid+1, righ

牛客小白月赛100(A,B,C,D,E,F三元环计数)

比赛链接 官方讲解 这场比较简单,ABC都很签到,D是个不太裸需要预处理的 B F S BFS BFS 搜索,E是调和级数暴力枚举,F是三元环计数。三元环考的比较少,没见过可能会偏难。 A ACM中的A题 思路: 就是枚举每个边变成原来的两倍,然后看看两短边之和是否大于第三边即可。 不能只给最短边乘 2 2 2,比如 1 4 8 这组数据,也不能只给第二短边乘 2 2 2,比

JS手写实现深拷贝

手写深拷贝 一、通过JSON.stringify二、函数库lodash三、递归实现深拷贝基础递归升级版递归---解决环引用爆栈问题最终版递归---解决其余类型拷贝结果 一、通过JSON.stringify JSON.parse(JSON.stringify(obj))是比较常用的深拷贝方法之一 原理:利用JSON.stringify 将JavaScript对象序列化成为JSO