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

相关文章

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Python内存管理机制之垃圾回收与引用计数操作全过程

《Python内存管理机制之垃圾回收与引用计数操作全过程》SQLAlchemy是Python中最流行的ORM(对象关系映射)框架之一,它提供了高效且灵活的数据库操作方式,本文将介绍如何使用SQLAlc... 目录安装核心概念连接数据库定义数据模型创建数据库表基本CRUD操作创建数据读取数据更新数据删除数据查

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Java中实现对象的拷贝案例讲解

《Java中实现对象的拷贝案例讲解》Java对象拷贝分为浅拷贝(复制值及引用地址)和深拷贝(递归复制所有引用对象),常用方法包括Object.clone()、序列化及JSON转换,需处理循环引用问题,... 目录对象的拷贝简介浅拷贝和深拷贝浅拷贝深拷贝深拷贝和循环引用总结对象的拷贝简介对象的拷贝,把一个

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

redis数据结构之String详解

《redis数据结构之String详解》Redis以String为基础类型,因C字符串效率低、非二进制安全等问题,采用SDS动态字符串实现高效存储,通过RedisObject封装,支持多种编码方式(如... 目录一、为什么Redis选String作为基础类型?二、SDS底层数据结构三、RedisObject

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

Java获取当前时间String类型和Date类型方式

《Java获取当前时间String类型和Date类型方式》:本文主要介绍Java获取当前时间String类型和Date类型方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录Java获取当前时间String和Date类型String类型和Date类型输出结果总结Java获取

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

java String.join()方法实例详解

《javaString.join()方法实例详解》String.join()是Java提供的一个实用方法,用于将多个字符串按照指定的分隔符连接成一个字符串,这一方法是Java8中引入的,极大地简化了... 目录bVARxMJava String.join() 方法详解1. 方法定义2. 基本用法2.1 拼接