深入浅出分析C++ string底层原理

目录
  • 一、深浅拷贝
    • 浅拷贝:
    • 深拷贝
  • 二、string迭代器原理
  • 三、string的传统写法
    • 1.构造实现
    • 2.其他接口

一、深浅拷贝

浅拷贝:

在实现string时要是不实先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(nullptr == str)
{
assert(false);
return;
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
~string()
{
if(_str)
{
delete[] _str;
_str = nullptr;
}
}
private:
char* _str;
};
// 测试
void Teststring()
{
string s1("hello bit!!!");
string s2(s1);
}

说明:上述string类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以 当继续对资源进项操作时,就会发生发生了访问违规。要解决浅拷贝问题,C++中引入了深拷贝。

深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

二、string迭代器原理

string迭代器实际上是这样的;

	    typedef char* Iterator;
		typedef const  char* const_Iterator;
		typedef char* reserve_Iterator;

实际上是指针靠begin(),end(),rend(),rbegin(),cend(),dbegin()这几个接口在做指针的前移和后移来遍历字符串。

		typedef char* Iterator;
		Iterator begin() {
			return str;
		}
		Iterator end() {
			return str + _size;
		}
		string::iterator it=s.begin();
		while(it!=s.end()){
		cout<<*it<<endl;
		}

这里已typedef char* Iterator来说明。接口begin()实际上时返回首指针,而end()时返回字符串的尾指针,靠++来移动指针。

三、string的传统写法

1.构造实现

首先要解决string的构造

string_str(const char* _str="")
			:_size(strlen(_str)),
			str(new char[strlen(_str) + 1]),
			_capasity(strlen(_str))
		{
			strcpy(str, _str);
		}
		string_str(string_str& st1)
			:str(new char[strlen(st1.str) + 1])
		{

			strcpy(this->str, st1.str);

		}

		~string_str() {
			delete[] str;
			str = nullptr;

		}

在实现构造函数时采深度拷贝,因为浅拷贝字符串在常量区是常量不能修改,采用深拷贝在堆区开辟空间,这样字符串就能修改了。
接着是无参构造,在string源码中无参构造对capacity初始化是15,而我在实现是初始化为0了。

	string_str(const string_str& st)
			:str(nullptr)
	{
			string_str tem(st.str);
			swap(this->str, tem.str);

		}

拷贝构造采用深拷贝,创建一个和this一样空间大小把str的内容拷贝到this中。

2.其他接口

operator=

	/*	string_str& operator=(const string_str& st) {
			if (this != &st) {
				char* s = new char[strlen(st.str) + 1];
				delete[] this->str;
				this->str = s;
				strcpy(this->str, st.str);

			}
			return *this;

		}*/

思想和拷贝构造基本相同采用深拷贝,创建一个和this一样空间大小把str的内容拷贝到this中。
reserve()

 void reserve(size_t num) {
			 if (num >= _capasity) {
				char* str1 = new char[num + 1]; 

				 strcpy( str1,this->str);

				 delete[] str;
				 this->str = str1;
					_capasity = num;

			 }
		 }

num如果比capacity小不做处理,比capacity大就进行扩容,开辟一个num大小空间的内存,接着把this中的内容拷到新开的内存。
push_back()和append()

		 void push_back(char ch) {
			 if (_size >= _capasity) {
				 size_t num = _capasity == 0 ? 4 : 2 * _capasity;
				 this->reserve(num);

			 }
			 str[_size] = ch;
			 _size++;
			 str[_size] = '\0';
			 //\0标志字符串结束

		 }
		 void append(const char* ch) {
			 size_t len = strlen(ch);
			 if (_size + len > _capasity) {
				 this->reserve(_size + len);
			 }
			 strcpy(this->str+_size,ch);
			 _size += len;

		 }

resize():

		void resize(size_t num,char ch='\0') {
			 if (num <= this->_size) {
				 this->str[num] = '\0';
				 this->_size = num;
			 }
			 else {

				 if (num >_capasity) {
					 reserve(num);
				 }
			 for (int i = _size; i < num; i++) {
				 str[i] = ch;
			}
			 _size = num;
			 str[num] = '\0';
			 }
		 }
		 size_t size() {

			 return _size;
		 }
		 size_t capacity() {
			 return _capasity;
		 }

分3中情况:
1.num比size()小,只需把\0加到str[size]处就行。
2.num比size大比capacpty小,把str中size到num复制为ch
3.num比capacpty大首先先扩容接着把size到num复制为ch。

到此这篇关于深入浅出分析C++ string底层原理的文章就介绍到这了,更多相关C++ String底层原理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ string字符串的修改与替换方法详析

    字符串内容的变化包括修改和替换两种.本节将分别讲解字符串内容的修改和字符串内容的替换. 字符串内容的修改 可以通过使用多个函数修改字符串的值.例如 assign(),operator=,erase(),交换(swap),插入(insert)等.另外,还可通过 append() 函数添加字符. 下面逐一介绍各成员函数的使用方法. assign()函数 使用 assign() 函数可以直接给字符串赋值.该函数既可以将整个字符串赋值给新串,也可以将字符串的子串赋值给新串.其在 basic_string

  • C++之string类对象的容量操作详解

    目录 前言 1. size返回字符串的有效长度 2. length 返回字符串的有效长度 3. capacity 返回总空间的大小 4. empty 检测是否为空串 5. clear 清空有效字符 6. resize 修改个数并填充 7. reserve 为字符串预留空间 总结 前言 hello,大家好,今天这期文章我们用来介绍string类对象的容量操作.希望对大家有所帮助,让我们开始吧. 1. size返回字符串的有效长度 返回字符串的长度,以字节为单位.这是符合字符串内容的实际字节数,不一

  • C++ 系统String类详解

    目录 一.C++ 系统String类 1.定义及初始化 2.类型大小 3.常用运算 1.赋值 2.加法 3.关系 4.常见的成员函数 1.下标操作 2.求串大小 3.返回c串(c语言中的字符串也叫c串) 4.查找 5.删除 6.交换swap 5.string类型数组 总结 一.C++ 系统String类 除了使用字符数组来处理字符串以外,c++引入了字符串类型.可以定义字符串变量. 1.定义及初始化 #include <iostream> #include <string.h> u

  • C++string容器基本概念详解

    string基本概念 本质: string是C++风格的字符串,而string本质上是一个类 string和char*区别: char*是一个指针 string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器. 特点: string类内部封装了很多成员方法 例如:查找find,拷贝copy,删除delete,替换replace,插入insert string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责. string构造函数 #includ

  • 深入探究C++ string的内部究竟是什么样的

    在C语言中,有两种方式表示字符串: 一种是用字符数组来容纳字符串,例如char str[10] = "abc",这样的字符串是可读写的: 一种是使用字符串常量,例如char *str = "abc",这样的字符串只能读,不能写. 两种形式总是以\0作为结束标志. C++ string 与它们在C语言中的前身截然不同.首先,也是最重要的不同点,C++ string 隐藏了它所包含的字符序列的物理表示.程序设计人员不必关心数组的维数或\0方面的问题. string 在内

  • C++string底层框架模拟实现代码

    目录 一. 前言 二. 浅拷贝与深拷贝优缺点 1. 浅拷贝 2. 深拷贝 3. 深拷贝现代版 4. 写时拷贝 三. string框架搭建 1. 框架定义 2. 构造函数 3. 析构函数 4. 赋值重载 5. 实现扩容 6. 增添数据 7. 删除数据 8. 数据查找 9. iterator迭代器 10. 插入/提取流与getline函数 四. 完整代码 一. 前言 本节文章主要说明浅拷贝和深拷贝的优缺点,以及仿写string类的逻辑并分析实现过程 如果人对一个事物感兴趣,总是那么好奇,就会刨根问底

  • C++中的string类型

    目录 1.string 类 1.1 和char *的异同 1.2 C++11初始化 1.3 拼接 1.4 长度 1.5 IO 1.6 原始字符串 1.string 类 1.1 和char *的异同 在C++当中,除了char *类型,还有专门的字符串类型,就叫做string. 通过包含头文件string就可以使用: include<string> 在很多方面,string类型的使用方法和char *一样,例如: string str1; string str2 = "hello wo

  • 深入浅出分析C++ string底层原理

    目录 一.深浅拷贝 浅拷贝: 深拷贝 二.string迭代器原理 三.string的传统写法 1.构造实现 2.其他接口 一.深浅拷贝 浅拷贝: 在实现string时要是不实先string拷贝构造,会自动生成一个拷贝构造函数,但是他只是一个浅拷贝.两个string对象指向同一个地址,在两个对象调用析构函数是,前一个对象调用的析构函数已经释放了这个地址的内从,而后一个会重复释放该块空间,导致出错. 会触发断点,然后报错. class string { public: /*string() :_st

  • Golang底层原理解析String使用实例

    目录 引言 String底层 stringStruct结构 引言 本人因为种种原因(说来听听),放弃大学学的java,走上了golang这条路,本着干一行爱一行的情怀,做开发嘛,不能只会使用这门语言,所以打算开一个底层原理系列,深挖一下,狠狠的掌握一下这门语言 废话不多说,上货 String底层 既然研究底层,那就得全方面覆盖,必须先搞一下基础的东西,那必须直接基本数据类型走起啊, 字符串String的底层我看就很基础 string大家应该都不陌生,go中的string是所有8位字节字符串的集合

  • Java 深入浅出分析Synchronized原理与Callable接口

    目录 一.基本特点 二.加锁工作过程 偏向锁 轻量级锁 重量级锁 三.其他的优化操作 锁消除 锁粗化 四.Callable 接口 一.基本特点 1. 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁. 2. 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁. 3. 实现轻量级锁的时候大概率用到的自旋锁策略 4. 是一种不公平锁 5. 是一种可重入锁 6. 不是读写锁 二.加锁工作过程 JVM 将 synchronized 锁分为 无锁.偏向锁.轻量级锁.重量级锁状态.会根据情况

  • CodeIgniter连贯操作的底层原理分析

    本文分析了CodeIgniter连贯操作的底层原理.分享给大家供大家参考,具体如下: php oop连贯操作原理 ->符号其实是传递对象指针的.或许这么说是不对的. 但是,我们可以这么的理解. 不多说.放代码. 普通用法: <?php class test { public $a=''; public $b=''; public function actiona() { $this->a="hello"; return $this; } public function

  • C++详细分析引用的使用及其底层原理

    目录 引用 引用的注意事项 引用做参数 实参传值和传引用的优劣 引用做函数返回值 传引用返回 引用的权限 引用经典笔试题 产生临时变量的情况 关于右值 引用的底层原理 引用 引用不是定义一个新变量,而是给已存在的变量取了一个外号,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间. 举个形象的例子,鲁智深又被叫做"花和尚",这里的花和尚和鲁智深都是同一个人,花和尚就是鲁智深的引用,说白了引用其实就是取外号. 引用的注意事项 1.引用必须初始化 int main() {

  • Python函数用法和底层原理分析

    目录 Python函数用法和底层分析 函数的基本概念 Python 函数的分类 核心要点 形参和实参 文档字符串(函数的注释) 返回值 函数也是对象,内存底层分析 变量的作用域(全局变量和局部变量) 部变量和全局变量效率测试 参数的传递 传递不可变对象的引用 浅拷贝和深拷贝 传递不可变对象包含的子对象是可变的情况 参数的几种类型 位置参数 默认值参数 命名参数 可变参数 强制命名参数 lambda 表达式和匿名函数 eval()函数 递归函数 Python函数用法和底层分析 函数是可重用的程序代

  • 通过实例解析JMM和Volatile底层原理

    这篇文章主要介绍了通过实例解析JMM和Volatile底层原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JMM和volatile分析 1.JMM:Java Memory Model,java线程内存模型 JMM:它是一个抽象的概念,描述的是线程和内存间的通信,java线程内存模型和CPU缓存模型类似,它是标准化的,用于屏蔽硬件和操作系统对内存访问的差异性. 2.JMM和8大原子操作结合 3.volatile的应用及底层原理探究 volat

  • Activiti工作流学习笔记之自动生成28张数据库表的底层原理解析

    网上关于工作流引擎Activiti生成表的机制大多仅限于四种策略模式,但其底层是如何实现的,相关文章还是比较少,因此,觉得撸一撸其生成表机制的底层原理. 我接触工作流引擎Activiti已有两年之久,但一直都只限于熟悉其各类API的使用,对底层的实现,则存在较大的盲区. Activiti这个开源框架在设计上,其实存在不少值得学习和思考的地方,例如,框架用到以命令模式.责任链模式.模板模式等优秀的设计模式来进行框架的设计. 故而,是值得好好研究下Activiti这个框架的底层实现. 我在工作当中现

  • spring aop底层原理及如何实现

    前言 相信每天工作都要用spring框架的大家一定使用过spring aop,aop的概念是面向切面编程,相对与传统的面向对象编程oop,aop更关注的是横向的逻辑,比如说一个大型系统中的日志记录,异常处理,性能监控等等,都是各个模块都需要的操作,那样代表着这些操作会散落在系统的各个地方,不易管理且杂乱无章,而aop就是关注的这些,aop将这些操作与业务代码分离,统一成一个个的切面,针对这些个切面进行编程处理.spring aop使得我们的aop开发工作变得简单,这次我就给大家讲讲spring

  • Java并发编程深入理解之Synchronized的使用及底层原理详解 下

    目录 一.synchronized锁优化 1.自旋锁与自适应自旋 2.锁消除 逃逸分析: 3.锁粗化 二.对象头内存布局 三.synchronized锁的膨胀升级过程 1.偏向锁 2.轻量级锁 3.重量级锁 4.各种锁的优缺点 接着上文<Java并发编程深入理解之Synchronized的使用及底层原理详解 上>继续介绍synchronized 一.synchronized锁优化 高效并发是从JDK 5升级到JDK 6后一项重要的改进项,HotSpot虚拟机开发团队在这个版本上花费了大量的资源

随机推荐