当前位置:   article > 正文

C++ string类(二)及深浅拷贝_std::string 浅拷贝

std::string 浅拷贝

一、string类方法使用举例

1.迭代器

迭代器本质:指针(理解)

迭代器:正向迭代器: begin() | end() 反向迭代器: rbegin() | rend()

2.find使用

  1. //找到s中某个字符
  2. void TestString3()
  3. {
  4. string s("AAADEFNUIENFUIAAA");
  5. //找到AAA位置
  6. size_t pos = s.find("AAA");
  7. cout << pos << endl;
  8. }

输出0,表示0位置处为AAA

3.获取文件后缀/substr

substr(pos = 0, n = npos);

从Pos位置开始,截取n个字符,如果n没有传递,表示从pos一直截取到末尾

如果都没有传递,截取整个字符

  1. void TestString3()
  2. {
  3. string s("124.text.cpp");
  4. //rfind从后面往前找 ’.’,+1找到后缀位置
  5. size_t pos =s.rfind('.') + 1;
  6. //从pos处截到末尾
  7. string postfix = s.substr(pos);
  8. cout << postfix << endl;
  9. }

4.给多行单词,获取每行单词中最后一个单词的长度/getline

  1. int main()
  2. {
  3. string line;
  4. // 不要使用cin>>line,因为会它遇到空格就结束了
  5. // while(cin>>line)
  6. while (getline(cin, line))
  7. {
  8. size_t pos = line.rfind(' ');
  9. cout << line.size() - pos - 1 << endl;
  10. }
  11. return 0;
  12. }

getline(cin,s): 获取一整行字符串,字符串中如果包含空格等空白字符也可以接收

oj练习

5.比大小

  1. void Test()
  2. {
  3. string s1("abc");
  4. string s2("afwef");
  5. if (s1 < s2)
  6. {
  7. cout << "s1<s2" << endl;
  8. }
  9. else if (s1>s2)
  10. {
  11. cout << "s1>s2" << endl;
  12. }
  13. else
  14. {
  15. cout << "s1=s2" << endl;
  16. }
  17. }

6.其他一些练习OJ

反转字母OJ

找第一个出现的相同的字符

验证回文串

二. string类的模拟实现

1. 浅拷贝

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规

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

2、解决浅拷贝的方法:深拷贝,写时拷贝(了解)

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

3.String类的模拟实现

正确实现String

深拷贝,传统版本
  1. class String
  2. {
  3. public:
  4. String(const char* str = "")
  5. {
  6. if (nullptr == str)
  7. str == "";
  8. _str = new char[strlen(str) + 1];
  9. strcpy(_str, str);
  10. }
  11. String(const String& s)
  12. :_str(new char[strlen(s._str) + 1])
  13. {
  14. strcpy(_str, s._str);
  15. }
  16.     String& operator=(const String& s)
  17.     {
  18.         if (this != &s)
  19.         {
  20.         char* pStr = new char[strlen(s._str) + 1];
  21.         strcpy(pStr, s._str);
  22.         delete[] _str;
  23.         _str = pStr;
  24.     }
  25. return *this;
  26. }
  27. ~String()
  28. {
  29. if (_str)
  30. {
  31. delete[]_str;
  32. _str = nullptr;
  33. }
  34. }
  35. private:
  36. char* _str;
  37. };
  38. void TestString()
  39. {
  40. String s1("hello");
  41. String s2(s1);
  42. String s3(s2);
  43. }
  44. int main()
  45. {
  46. TestString();
  47. return 0;
  48. }

如下,每个对象都有自己独立的空间,释放时也是,只释放自己的互不影响

深拷贝(现代版写法)

减少传统代码重复,相似性代码进行优化

  1. class String
  2. {
  3. public:
  4.     String(const char* str = "")
  5.     {
  6.         if (nullptr == str)
  7.         {
  8.            assert(false);
  9.             return;
  10.         }
  11.         _str = new char[strlen(str) + 1];
  12.         strcpy(_str, str);
  13.     }
  14.     String(const String& s)
  15.        : _str(nullptr)//_Str可能为随机指针,要先置为空
  16.     {
  17.         String strTmp(s._str);
  18.         swap(_str, strTmp._str);//交换地址
  19.     }
  20.     String& operator=(String s)//赋值运算符重载,先传入参数
  21.     {
  22.         swap(_str, s._str);//
  23.         return *this;
  24.     }

4.写时拷贝

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

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

三、string模拟实现代码(全部)

  1. #include <assert.h>
  2. #include<iostream>
  3. #include<string>
  4. using namespace std;
  5. namespace zx
  6. {
  7. class string
  8. {
  9. public:
  10. typedef char* iterator;
  11. ///
  12. // 构造
  13. string(const char* str = "")
  14. {
  15. if (nullptr == str)
  16. str = "";
  17. _size = strlen(str);
  18. _capacity = _size;
  19. _str = new char[_capacity + 1];
  20. strcpy(_str, str);
  21. }
  22. string(const string& s)
  23. {
  24. string temp(s._str);
  25. this->swap(temp);
  26. }
  27. string(size_t n, char val)
  28. {
  29. _str = new char[n + 1];
  30. memset(_str, val, n);
  31. _str[n] = '\0';
  32. _size = n;
  33. _capacity = n;
  34. }
  35. string& operator=(string s)
  36. {
  37. this->swap(s);
  38. return *this;
  39. }
  40. ~string()
  41. {
  42. if (_str)
  43. {
  44. delete[] _str;
  45. _str = nullptr;
  46. _capacity = 0;
  47. _size = 0;
  48. }
  49. }
  50. /
  51. // 迭代器
  52. iterator begin()
  53. {
  54. return _str;
  55. }
  56. iterator end()
  57. {
  58. return _str + _size;
  59. }
  60. /
  61. // 容量
  62. size_t size()const
  63. {
  64. return _size;
  65. }
  66. size_t length()const
  67. {
  68. return _size;
  69. }
  70. size_t capacity()const
  71. {
  72. return _capacity;
  73. }
  74. bool empty()const
  75. {
  76. return 0 == _size;
  77. }
  78. void clear()
  79. {
  80. _size = 0;
  81. }
  82. void resize(size_t newsize, char val)
  83. {
  84. size_t oldsize = size();
  85. if (newsize > oldsize)
  86. {
  87. // 有效元素个数增多
  88. if (newsize > capacity())
  89. reserve(newsize);
  90. // 多出的元素使用val填充
  91. memset(_str + _size, val, newsize - _size);
  92. }
  93. _size = newsize;
  94. _str[_size] = '\0';
  95. }
  96. void resize(size_t newsize)
  97. {
  98. resize(newsize, '\0');
  99. }
  100. void reserve(size_t newcapacity)
  101. {
  102. size_t oldcapacity = capacity();
  103. if (newcapacity > oldcapacity)
  104. {
  105. // 1. 申请新空间
  106. char* temp = new char[newcapacity + 1];
  107. // 2. 拷贝元素
  108. strncpy(temp, _str, _size);
  109. // 3. 释放旧空间
  110. delete[] _str;
  111. // 4. 使用新空间
  112. _str = temp;
  113. _capacity = newcapacity;
  114. _str[_size] = '\0';
  115. }
  116. }
  117. // 元素访问
  118. char& operator[](size_t index)
  119. {
  120. assert(index < _size);
  121. return _str[index];
  122. }
  123. const char& operator[](size_t index)const
  124. {
  125. assert(index < _size);
  126. return _str[index];
  127. }
  128. char& at(size_t index)
  129. {
  130. // 如果越界,抛出out_of_range的异常
  131. return _str[index];
  132. }
  133. const char& at(size_t index)const
  134. {
  135. // 如果越界,抛出out_of_range的异常
  136. return _str[index];
  137. }
  138. //
  139. // modify
  140. void push_back(char ch)
  141. {
  142. *this += ch;
  143. }
  144. string& operator+=(char ch)
  145. {
  146. if (_size == _capacity)
  147. reserve((size_t)_capacity*1.5 + 3);
  148. _str[_size] = ch;
  149. ++_size;
  150. _str[_size] = '\0';
  151. return *this;
  152. }
  153. string& operator+=(const char* str)
  154. {
  155. size_t needSpace = strlen(str);
  156. size_t leftSpace = capacity() - size();
  157. if (needSpace > leftSpace)
  158. {
  159. reserve(capacity()+ needSpace);
  160. }
  161. strcat(_str, str);
  162. _size += needSpace;
  163. _str[_size] = '\0';
  164. return *this;
  165. }
  166. string& operator+=(const string& s)
  167. {
  168. *this += s.c_str();
  169. return *this;
  170. }
  171. string& append(const char* str)
  172. {
  173. *this += str;
  174. return *this;
  175. }
  176. string& appent(const string& s)
  177. {
  178. *this += s;
  179. return *this;
  180. }
  181. string& insert(size_t pos, const string& s);
  182. string& erase(size_t pos = 0, size_t n = npos);
  183. void swap(string& s)
  184. {
  185. std::swap(_str, s._str);
  186. std::swap(_size, s._size);
  187. std::swap(_capacity, s._capacity);
  188. }
  189. const char* c_str()const
  190. {
  191. return _str;
  192. }
  193. size_t find(char ch, size_t pos = 0)const
  194. {
  195. if (pos >= _size)
  196. {
  197. return npos;
  198. }
  199. for (size_t i = pos; i < _size; ++i)
  200. {
  201. if (_str[i] == ch)
  202. return i;
  203. }
  204. return npos;
  205. }
  206. size_t rfind(char c, size_t pos = npos)
  207. {
  208. if (pos >= _size)
  209. {
  210. pos = _size-1;
  211. }
  212. for (int i = pos; i >= 0; --i)
  213. {
  214. if (_str[i] == c)
  215. return i;
  216. }
  217. return npos;
  218. }
  219. string substr(size_t pos = 0, size_t n = npos) const
  220. {
  221. // 从pos位置开始,往后借助n个字符长度
  222. if (pos >= _size)
  223. {
  224. return string();
  225. }
  226. // 从pos到字符串的末尾剩余字符个数
  227. n = min(n, _size - pos);
  228. string temp(n, '\0');
  229. size_t index = 0;
  230. for (size_t i = pos; i < pos+n; ++i)
  231. {
  232. temp[index++] = _str[i];
  233. }
  234. return temp;
  235. }
  236. private:
  237. char* _str;
  238. size_t _size;
  239. size_t _capacity;
  240. const static size_t npos = -1;
  241. friend ostream& operator<<(ostream& out, const string& s);
  242. };
  243. ostream& operator<<(ostream& out, const string& s)
  244. {
  245. for (size_t i = 0; i < s.size(); ++i)
  246. {
  247. cout << s[i];
  248. }
  249. return out;
  250. }
  251. }
  252. int main()
  253. {
  254. // TestMyString01();
  255. // TestMyString02();
  256. // TestMyString03();
  257. TestMyString04();
  258. _CrtDumpMemoryLeaks();
  259. return 0;
  260. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/501747
推荐阅读
相关标签
  

闽ICP备14008679号