C++ ------>std::string--->深浅拷贝
  L8iEHH07GzZb 2023年11月02日 22 0

各位好友, 本期 正式开启 string 深浅拷贝探究 !下面, 让我们开始 ---->战斗环节 !

先来了解一下, 浅拷贝 --------->程序运行 ------->如下 :>

C++ ------>std::string--->深浅拷贝_模拟实现 字符串大小比较

首先, 什么是 浅拷贝 ?

---------->浅拷贝, 也称 位拷贝, 编译器只是将对象中的值拷贝过来。

--------->如果对象中有资源管理, 就会导致多个对象共同享用一份资源。(关键点)

当一个对象被销毁 ---->会将该资源释放掉 ! 其他对象不知道该资源已被释放, 认为还有效 !

所以 ----->会继续对该资源进行访问使用 !   ----->这个时候, 就会发生上述现象的违规访问 !


显然, 上述程序崩溃的原因 :>

string没有显示定义其拷贝构造函数赋值运算符重载 此时编译器会合成默认的 。

当用 T1 构造 T2 时, 编译器会去调用默认的拷贝构造。最终导致的问题, T1 与 T2 共同使用一块内存空间 !

------------------------->从而, 在多次释放同一块内存空间的时候,引发 程序崩溃。 这种方式, 称为 浅拷贝 !

为了方便好友们, 有更好地理解, 现附上 图示解析, 如下 :>

C++ ------>std::string--->深浅拷贝_String 类深浅拷贝_02


显然要解决上述问题, 即 不要让同一个资源 去共享即可 !而这就是 深拷贝的核心思想 !代码如下 :>

//···
·······//
 //构造函数
string(const char* str = " ")
{
	_size = strlen(str);
  _capacity = _size;
  
  _str = new char[_capacity + 1];
  
  memcpy(_str, s._str, _size + 1);
  
  //strcpy(_str, str);----->特殊情况下 追加‘\0’则不行
}
//深拷贝 ~~ 模块代码
string(const string& s)
{
	_str = new char[s._capacity + 1];
  
  memcpy(_str, s._str, s._size + 1);
  
  //strcpy(_str, s._str);
  _size = s._size;
  _capacity = s._capacity;
}

//析构函数
~string()
{
	delete[] _str;
  _str = nullptr;
  
  _size = _capacity = 0;
}

//深拷贝 ---->测试环节
int main()
{
	UC :: string T1("I like sport !");
  UC :: string T2(T1);
  
  cout << T2.c_str() <<endl;
}

为了方便好友们, 有更好地观感体验, 现附上 有彩色的代码图样 !如下 :>

C++ ------>std::string--->深浅拷贝_赋值重载 ‘ = ’_03


深拷贝 ~~ 测试 ----->运行结果 :>

C++ ------>std::string--->深浅拷贝_赋值重载 ‘ = ’_04


为了方便好友们, 更好地理解 ---->深拷贝  现 如下 :>

C++ ------>std::string--->深浅拷贝_特殊情况__追加 ‘ src="//dev-img.mos.moduyun.com/20231028/9fff4c85-8649-4e6c-9ee4-4a692d356f97.png" ’_05


各位好友,解析 深拷贝 已完成 !现 深入探讨 深拷贝 会遇到的一些特殊情况 !请看下列图示 :>

C++ ------>std::string--->深浅拷贝_赋值重载 ‘ = ’_06

string 对象在进行 拷贝构造 新的 String 对象时候, 发生了 程序崩溃 !

由上图可知, 增加了 一个特殊字符  ‘\0’  发生了 程序 错误 !可见 深拷贝的函数设计存在 不足性

------------------>原因:>strcpy()函数的运用, 其本身存在 局限性 ---->会 遇到 ‘\0’  终止拷贝 !

因此, 在 C 语言上, 就设计了 一个 memcpy 函数。  该函数, 不会   ‘\0’  存在就终止 其拷贝过程


再强化 :>

strcpy()函数 遇到  ‘\0’  发生终止, 而 memcpy()则不会

memecpy()---->会拷贝完 n个字节。如果第二个字符串中没有 n个字节怎么办? 依然能拷贝成功。

C++ ------>std::string--->深浅拷贝_String 类深浅拷贝_07

-------->上述实现, 用到了重载操作符  “<<”  (流输出 )

而流输出 “<<” 会将 所得到的全部字符 统统打印出来, 这同 底层 ~~ 实现原理有关 !

----------------------------------------->而有了 流输出 “<<”  自然不能忘记 流提取  “>>” 

代码如下 :>

//清除函数 clear()

void clear()
{
	_str[0] = ' \0 ';
  
  _size = 0;
}

//流输出 " << "
ostream& operator<<(ostream& out, const string& s)
{
	for(auto e : s)
  {
  	cout << e << endl;
  }
}

//流提取 “ >> ”
istream& operator>>(istream& in, string& s)
{
	s.clear();
  
  char ch = in.get();
  
  //处理缓存区内的 空格 与换行
  while(ch == ' ' || ch == ' \n ')
  {
  		ch = in.get();
  }
  
  char buff[128];
  int i = 0;
  while(ch == ' ' && ch == ' \n ')
  {
  	buff[i++] = ch;
    
    if(i == 127)
    {
    	buff[i] = ' \0 ';
      
      s += buff;
      i = 0;
    }
    
    ch = in.get();
  }
  
  if(i != 0)
  {
  	buff[i] = ' \0 ';
    
    s += buff;
  }
  
  return in;
}

为了方便好友们, 有更好地观感体验, 现附上 有彩色的代码图样 !如下 :>

C++ ------>std::string--->深浅拷贝_模拟实现 字符串大小比较_08


经调试 可得知 :>

C++ ------>std::string--->深浅拷贝_流输入___刘提取_09

现对 ----->流输出 ~~ 流提取 进行解析  :>

流输出 “ostream <<”  底层逻辑 走的是 迭代器部分 !

流提取 “ostream >>”  底层实现原理 是将得到的每一个字符 储存在一个临时的空间数组(栈区)上

--------------------------->之后 ----->用到 “追加字符串”  实现函数 !经 *this 返回, 指向 流提取 形参 in 


各位好友, 下面继续推进 -------->string 类拷贝构造 ------->新的玩法:>赋值重载 “operator=”

----->传统写法 :>

//传统写法
// 赋值重载运算符 “operator=” 运用
string& operator=(const string& s)
{
	if(this != &s) //注意此处 “!=” 并没有,自定义 !!
  {
  	char* tmp = new char[s._capacity + 1];
    delete[] _str;
    _str = nullptr;
    _str = tmp;
    
    _size = s._size;
    _capacity = s._capacity;
  }
  
  return *this;
}

//可单独对 交换函数 swap() 进行定义封装 
void swap(string& s)
{
	std :: swap(_str, s._str);
  std :: swap(_size, s._size);
  std :: swap(_capacity, s._capacity);
}

//现代写法 --->第一种写法
string& operator=(const strng& s)
{
	if(this != &s)
  {
  	string tamp(s);
    
    //库里面有一个 交换函数, 别忘了 展开 “std :: swap”
    std :: swap(_str. tamp._str);
    std :: swap(_size, tamp._size);
    std :: swap(_capacity, tamp._capacity);
  }
  
  return *this;
}

//现代写法 --->第二种写法
string& operator=(const strng& s)
{
	if(this != &s)
  {
  	string tamp(s);
   	
    //新手玩法:this ->swap(tamp);
    swap(tamp);
  }
  
  return *this;
}

//优化版 ---->现代写法
string& operator=(string tamp)
{
	swap(tamp);
  
  return *this;
}

//重载运算符 “ == ”
bool operartor==(const string& s) const
{
  return _size == s._size
    && memcmp(_str, s._str, _size) == 0; 
}

//重载运算符 “ != ”
bool operator!=(const string& s) const
{
	return !(*this == &s);
}

为了方便好友们, 有更好地观感体验, 现附上 有彩色的代码图样:>

C++ ------>std::string--->深浅拷贝_String 类深浅拷贝_10


C++ ------>std::string--->深浅拷贝_赋值重载 ‘ = ’_11


现 对上述代码, 进行解析回顾 :>

难点一 :>不再交换 内置类型成员 ----->更换成如下形式 :>

C++ ------>std::string--->深浅拷贝_模拟实现 字符串大小比较_12

上述改写, 会造成程序 执行, 引发 栈区溢出   ----->赋值操作会一直进行下去 !


难点二 :>现代写法 理解 ,代码如下 :>

//string 重载赋值 “ = ” 升级版现代写法
string& operator=(string tamp)
{
	swap(tamp);
  return *this;
} //注意 :>swap()交换函数, 可以调用 库里面的;也可以自己实现 !

------>

为了方便好友们, 有更好地观感体验, 现附上 有彩色的代码图样 :>

C++ ------>std::string--->深浅拷贝_模拟实现 字符串大小比较_13

C++ ------>std::string--->深浅拷贝_String 类深浅拷贝_14


各位好友,传统写法 需要手动申请空间 ----->手动拷贝复制 ----->再手动释放相关空间 !

-------------------------------------------->现代写法,全是自动实现 ~~ 自动调用相关接口 !

C++ ------>std::string--->深浅拷贝_流输入___刘提取_15

经调试可知 :>变量 tamp 去调用 深拷贝   ------->拷贝 T1 对象的字符串 “sport”

------>进行交换, 将 tamp 内的值 交换给 T2  ------>最后一步, 就是析构函数的调用, 释放内存 !

为了加深理解, 请看下面的 流程分析图 :>

C++ ------>std::string--->深浅拷贝_特殊情况__追加 ‘ src="//dev-img.mos.moduyun.com/20231028/f6c2e343-d565-49dd-b84f-065bc3bcafa2.png" ’_16


下面继续进行 一个 字符串大小的比较  ---->代码如下 :>

------>头文件 “string.h”

//字符串大小比较

bool operator==(const string& s) const
{
	return _size == s._size && memcmp(_str, s._str, _size) == 0;
}

//小于 “ < ” 第一种写法
bool operator<(const string& s) const
{
	size_t i1 = 0;
  size_t i2 = 0;
  while(i1 < _size && i2 < s._size)
  {
  	if(_str[i1] < s._str[i2])
  	{
  		return true;
  	}
  	else if(_str[i1] > s._str[i2])
  	{
    	return false;
  	}
  	else
  	{
  		i1++;
    	i2++;
  	}	
  }
}
//小于 “ < ” 第二种写法
bool operator<(const string& s) const
{
	int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size);
  
  return ret == 0 ? _size < s._size : ret < 0;
}
bool operator<=(const string& s) const
{
	return *this < s || *this == s;
}
bool operator>(const string& s) const
{
	return !(*this <= s);
}
bool operator>=(const string& s) const
{
	return !(*this < s);
}
bool operator!=(const string& s) const
{
	return !(*this == s);
}



------>测试部分 “Test.cpp”

//string 字符串大小比较测试

int main()
{
	string T1("sport");
  string T2("sport");
  
  cout << (T1 == T2) << endl;
  cout << (T1 < T2) << endl;
  cout << (T1 > T2) << endl;
  
  string T3("sport");
  string T4("sportxxx");
  
  cout << (T3 == T4) << endl;
  cout << (T3 < T4) << endl;
  cout << (T3 > T4) << endl;
  
  string T5("soprtxxx");
  string T6("sport");
  
  cout << (T5 == T6) << endl;
  cout << (T5 < T6) << endl;
  cout << (T5 > T6) >> endl;
}

为了方便好友们, 有更好地观感体验, 现附上 有彩色的代码图样 :>

----->头文件部分 “string.h”

C++ ------>std::string--->深浅拷贝_模拟实现 字符串大小比较_17


----->测试环节:>

C++ ------>std::string--->深浅拷贝_赋值重载 ‘ = ’_18


各位好友, 本章节  String 深浅拷贝 ---->已讲解完成 !😊

------------------->下一期 开战 Vector(容器)环节 !    ----------->敬请期待 "😊😊


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

L8iEHH07GzZb