深拷贝与浅拷贝

首先来看一段代码

#include <iostream>
#include <string.h>
#include <assert.h>class String{public:String(const char* str = ""){assert(str != nullptr);_str = new char[strlen(str) + 1];strcpy(_str, str);}~String(){if(_str){delete[] _str;_str = nullptr;}}private:char* _str;
};int main(){String s1("hello, world!");String s2(s1);return 0;
}

这个简单的String类有没有问题呢?我们使用的是默认的拷贝构造函数,我们来运行一下

浅拷贝

这是为什么呢?为什么new开辟的空间会被释放两次

从上图,我们可以看出,使用s1拷贝构造s2就是将s1中的_str的值拷贝给了s2中的_str导致s1._str与s2._str指向了同一块空间。因此在程序结束时,s1和s2分别调用各自的析构函数,所以同一块空间就被delete[]两次,这显然是不行的。
动态申请的空间是不能释放两次的,因为第一次释放,该空间就已经还给系统,再第二次释放之前,有可能该空间已经分配给其他用户,所以第二次释放有可能释放的是其他用户申请的空间,这显然是不合理的。
上述这种问题就是由于浅拷贝造成的。从上面的例子中,我们大概可以明白什么是浅拷贝。
浅拷贝就是将对象中的值拷贝过来,如果对象中管理了堆中的资源,最后会导致多个对象共享同一份资源。

深拷贝


如上图所示就是深拷贝。为每个对象独立分配资源,保证多个对象之间不会因为共享资源而导致资源被多次释放。

写时拷贝

写时拷贝就是一种拖延症,是在浅拷贝的基础上增加了引用计数的方式来实现的。写时拷贝在写的时候(即改变字符串的时候)才会真正开辟空间进行深拷贝,如果只是对数据的读,则只会进行浅拷贝
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象是资源的最后一个使用者,将该资源释放否则就不能释放,因为还有其他对象在使用该资源

string类的模拟实现

string.h

#pragma once#include <iostream>
#include <assert.h>
#include <string.h>class String{friend std::ostream& operator<<(std::ostream& _cout, const String& s);friend std::istream& operator>>(std::istream& _cin, String& s);public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}public:String(const char* str = ""): _str(nullptr), _capacity(0){assert(str != nullptr);_size = strlen(str);reserve(_size);strcpy(_str, str);}~String(){if(_str){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}}String(const String& s): _str(nullptr), _size(0), _capacity(0){String temp(s.c_str());swap(temp);}String& operator=(String s){swap(s);return *this;}public:void reserve(size_t capacity);void resize(size_t size, char ch = 0);public:String& operator+=(char ch);String& operator+=(const char* str);String operator+(char ch) const;String operator+(const char* str) const;char& operator[](size_t pos);const char& operator[](size_t pos) const;public:String& insert(size_t pos, char ch);String& insert(size_t pos, const char* str);String& push_back(char ch);String& append(const char* str);String& erase(size_t pos, size_t len = -1);size_t find(char ch, size_t pos = 0) const;size_t find(const char* str, size_t pos = 0) const;public:bool operator>(const String& s) const;bool operator==(const String& s) const;bool operator>=(const String& s) const;bool operator<(const String& s) const;bool operator<=(const String& s) const;bool operator!=(const String& s) const;public:size_t size() const{return _size;}size_t capacity() const{return _capacity;}char* c_str() const{return _str;}void swap(String& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}private:char* _str;size_t _size;size_t _capacity;
};std::ostream& operator<<(std::ostream& _cout, const String& s);std::istream& operator>>(std::istream& _cin, String& s);

string.cpp

#include "string.h"void String::reserve(size_t capacity){if(capacity > _capacity || capacity == 0){if(capacity % 8 == 0){capacity += 8;}else{capacity = (capacity / 8 + 1) * 8;}char* temp = new char[capacity];if(_str){strcpy(temp, _str);}delete[] _str;_str = temp;_capacity = capacity - 1;}
}void String::resize(size_t size, char ch){if(size <= _size){_size = size;}else if(size <= _capacity){for(size_t i = _size; i < size; ++i){_str[i] = ch;}_size = size;}else{reserve(size);for(size_t i = _size; i < size; ++i){_str[i] = ch;}_size = size;}_str[_size] = '\0';
}String& String::insert(size_t pos, char ch){assert(pos <= _size);++_size;if(_size > _capacity){reserve(_capacity * 2);}for(int i = _size; i > (int)pos; --i){_str[i] = _str[i - 1];}_str[pos] = ch;return *this;
}String& String::insert(size_t pos, const char* str){assert(pos <= _size);int len = strlen(str);_size += len;if(_size > _capacity){reserve(_size);}for(int i = _size; i >= (int)pos + len; --i){_str[i] = _str[i - len];}strncpy(_str + pos, str, len);return *this;
}String& String::push_back(char ch){insert(_size, ch);return *this;
}String& String::append(const char* str){insert(_size, str);return *this;
}String& String::erase(size_t pos, size_t len){assert(pos < _size);if(len >= _size - pos - 1){_size = pos;_str[_size] = '\0';}else{for(int i = pos; i < (int)_size; ++i){_str[i] = _str[i + len];}}return *this;
}size_t String::find(char ch, size_t pos) const{for(int i = pos; i < (int)_size; ++i){if(_str[i] == ch){return i;}}return -1;
}size_t String::find(const char* str, size_t pos) const{char* temp = strstr(_str + pos, str);if(!temp){return -1;}return temp - _str;
}String& String::operator+=(char ch){insert(_size, ch);return *this;
}String& String::operator+=(const char* str){insert(_size, str);return *this;
}String String::operator+(char ch) const{String temp(*this);temp += ch;return temp;
}String String::operator+(const char* str) const{String temp(*this);temp += str;return temp;
}char& String::operator[](size_t pos){return *(_str + pos);
}const char& String::operator[](size_t pos) const{return *(_str + pos);
}bool String::operator>(const String& s) const{int ret = strcmp(_str, s._str);if(ret > 0){return true;}return false;
}bool String::operator==(const String& s) const{int ret = strcmp(_str, s._str);if(!ret){return true;}return false;
}bool String::operator>=(const String& s) const{return *this > s || *this == s;
}bool String::operator<(const String& s) const{return !(*this >= s);
}bool String::operator<=(const String& s) const{return !(*this > s);
}bool String::operator!=(const String& s) const{return !(*this == s);
}std::ostream& operator<<(std::ostream& _cout, const String& s){for(size_t i = 0; i < s.size(); ++i){_cout << s[i];}_cout << std::endl;return _cout;
}std::istream& operator>>(std::istream& _cin, String& s){if(s._str){delete[] s._str;s._str = nullptr;s._size = 0;s._capacity = 0;}char* temp = new char[2048];_cin >> temp;int len = strlen(temp);s.reserve(len);strcpy(s._str, temp);delete[] temp;temp = nullptr;s._size = len;return _cin;
}

『C++』string类模拟实现相关推荐

  1. 『TensorFlow』批处理类

    『教程』Batch Normalization 层介绍 基础知识 下面有莫凡的对于批处理的解释: fc_mean,fc_var = tf.nn.moments(Wx_plus_b,axes=[0],# ...

  2. 『GoLang』string及其相关操作

    1. 字符串简介 双引号:字符串使用双引号括起来,其中的相关的转义字符将被替换 str := "Hello World! \n Hello Gopher! \n" 输出: Hell ...

  3. 『TensorFlow』专题汇总

    TensorFlow函数查询 『TensorFlow』0.x_&_1.x版本框架改动汇总 『TensorFlow』函数查询列表_数值计算 『TensorFlow』函数查询列表_张量属性调整 『 ...

  4. 【C++篇】STL常见容器String的模拟实现

    准备 博主:大大怪先森(记得关注哦!) 编程环境:vs2013 所示代码:码源 文章目录 准备 前言 一.标准库中的tring类 1.了解类 2.string类的常见接口 2.1 string类对象的 ...

  5. C++ string类(包括深浅拷贝)

    目录 一.字符码表 一.为什么用string类 二.使用标准库中的string类 1.string类 2.string中的常用接口说明 (1)string类对象的常见构造 (2)string类对象访问 ...

  6. C++ STL : 模拟实现STL中的string类

    string的文档介绍 string是表示字符序列的类 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作 单字节字符字符串的设计特性. string类是使用c ...

  7. 『电子书』分享一波码农必备编程开发类书籍[转]

    分享一些书籍 看到书籍很多,感觉很不错,就收藏下来了,是百度盘的连接,失效的可以评论一下以此更新一下连接. 书籍清单 Python编程快速上手 细说PHP(第2版) Python核心编程(第3版) L ...

  8. 内存分布malloc/calloc/realloc/free/new/delete、内存泄露、String模板、浅拷贝与深拷贝以及模拟string类的实现

    内存分布 一.C语言中的动态内存管理方式:malloc/calloc/realloc和free 1.malloc: 从堆上获得指定字节的内存空间,函数声明:void *malloc (int n); ...

  9. String类的模拟实现

    目录: 一.经典String类的问题 1,浅拷贝 2,深拷贝 二.现代写法版的string类 三.传统String类的模拟实现 1.迭代器 2.operator[] 3.size() 4.c_str( ...

最新文章

  1. 027_自己实现一个ArrayList
  2. c语言高中题目及答案,高中信息技术 C语言程序设计练习题 选修1
  3. 需要排序的最短子数组长度
  4. Fence Repair
  5. 数据库主键设计之思考(转)
  6. Largest Rectangle in a Histogram (动态规划+奇思妙想单调栈)求最大矩状图面积
  7. php将年月日_php生成年月日下载列表的方法
  8. Linux下VNCSERVER的使用介绍
  9. MapReduce案例
  10. 阿里云推出香港高防IP服务 为中国企业出海安全护航
  11. 结合Control.FirefoxDialog控件,构造优秀的参数配置管理模块
  12. python2安装pip2(python3安装pip)
  13. Java实现仿QQ登陆、好友界面(可连接数据库)
  14. MacOS删除开机启动项
  15. 计算机导论论文论题,计算机导论专业论文题目 计算机导论毕业论文题目怎么定...
  16. AutoCAD 2021-2022
  17. vue写一个翻页的时间插件
  18. 如何将电脑文件自动备份?
  19. 为什么要阅读——兼分享《首先,打破一切常规》[中译文]:世界顶级管理者的成功秘诀/(美)马库斯·白金汉,(美)柯特·科夫曼 著
  20. 前端面经 300条,背完这些就够了!

热门文章

  1. java软件学习网站_Java程序员必看的十大学习网站
  2. java验证网址正常打开_JSP 页面访问用户验证
  3. 【图神经网络实战】深入浅出地学习图神经网络GNN(下)
  4. VBA自学应用(2)——制作简单的数据录入窗口
  5. 浏览器兼容模式中文乱码
  6. Xcode6 中iphone5s(7.1)模拟器无法全屏
  7. 关于QOSEC病毒的...不知道名字..已经搞掂
  8. Topic exercises
  9. 多域名实现单点登录详解
  10. Netty之UDP协议开发