String类的实现(4)写时拷贝浅析
由于释放内存空间,开辟内存空间时花费时间,因此,在我们在不需要写,只是读的时候就可以不用新开辟内存空间,就用浅拷贝的方式创建对象,当我们需要写的时候才去新开辟内存空间。这种方法就是写时拷贝。这也是一种解决由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃的问题。这种方法同样需要用到引用计数:使用int *保存引用计数;采用所申请的4个字节空间。
#include<iostream>
#include<stdlib.h>
using namespace std;
class String
{
public:
String(const char *pStr = "")
{
if (pStr == NULL)
{
_pStr = + ];
*((;
_pStr = ();
*_pStr = '\0';
}
else
{
_pStr = + ];
my_strcopy(_pStr, pStr);
*(() = ;
}
}
String(const String& s)
:_pStr(s._pStr)
{
++GetCount();
}
~String()
{
Release();
}
String& operator=(const String& s)
{
if (this != &s)
{
Release();
_pStr = s._pStr;
--(GetCount());
}
return *this;
}
char& operator[](size_t index)//写时拷贝
{
) //当引用次数大于1时新开辟内存空间
{
+ ];
my_strcopy(pTem + , _pStr);
--GetCount(); //原来得空间引用计数器减1
_pStr = pTem + ;
GetCount() = ;
}
return _pStr[index];
}
const char& operator[](size_t index)const
{
return _pStr[index];
}
friend ostream& operator<<(ostream& output, const String& s)
{
output << s._pStr;
return output;
}
private:
int& GetCount()
{
);
}
void Release()
{
== --GetCount()))
{
_pStr = ();
delete _pStr;
}
}
char *_pStr;
};
int main()
{
String s1;
String s2 = ";
String s3(s2);
s2[] = ';
String s4;
s3 = s4;
}
写时拷贝能减少不必要的内存操作,提高程序性能,但同时也是一把双刃剑,如果没按 stl 约定使用 String ,可能会导致极其严重的 bug ,而且通常是很隐蔽的,因为一般不会把注意力放到一个赋值语句。修改 String 数据时,先判断计数器是否为 0( 0 代表没有其他对象共享内存空间),为 0 则可以直接使用内存空间(如上例中的 s2 ),否则触发写时拷贝,计数 -1 ,拷贝一份数据出来修改,并且新的内存计数器置 0 ; string 对象析构时,如果计数器为 0 则释放内存空间,否则计数也要 -1 。
写时拷贝存在的线程安全问题
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。String类写时拷贝可能存在的问题详见:http://blog.csdn.net/haoel/article/details/24077
String类的实现(4)写时拷贝浅析的更多相关文章
- 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)
标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...
- String 类的实现(2)引用计数与写时拷贝
1.引用计数 我们知道在C++中动态开辟空间时是用字符new和delete的.其中使用new test[N]方式开辟空间时实际上是开辟了(N*sizeof(test)+4)字节的空间.如图示其中保存N ...
- String写时拷贝实现
头文件部分 1 /* 版权信息:狼 文件名称:String.h 文件标识: 摘 要:对于上版本简易的String进行优化跟进. 改进 1.(将小块内存问题与大块分别对待)小内存块每个对象都有,当内存需 ...
- 计算机程序的思维逻辑 (73) - 并发容器 - 写时拷贝的List和Set
本节以及接下来的几节,我们探讨Java并发包中的容器类.本节先介绍两个简单的类CopyOnWriteArrayList和CopyOnWriteArraySet,讨论它们的用法和实现原理.它们的用法比较 ...
- 并发容器之写时拷贝的 List 和 Set
对于一个对象来说,我们为了保证它的并发性,通常会选择使用声明式加锁方式交由我们的 Java 虚拟机来完成自动的加锁和释放锁的操作,例如我们的 synchronized.也会选择使用显式锁机制来主动的控 ...
- Java编程的逻辑 (73) - 并发容器 - 写时拷贝的List和Set
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- 写时拷贝(Copy On Write)方案详解
本文旨在通过对 写时拷贝 的四个方案(Copy On Write)分析,让大家明白写时拷贝的实现及原理. 关于浅拷贝与深拷贝,我在之前的博客中已经阐述过了 浅拷贝容易出现指针悬挂的问题,深拷贝效率低 ...
- rust漫游 - 写时拷贝 Cow<'_, B>
rust漫游 - 写时拷贝 Cow<'_, B> Cow 是一个写时复制功能的智能指针,在数据需要修改或者所有权发生变化时使用,多用于读多写少的场景. pub enum Cow<'a ...
- Linux写时拷贝技术(copy-on-write)
COW技术初窥: 在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,linux中引入了“写时复制“技术,也就是只有进程空间的各段的内 ...
随机推荐
- android学习4——View的长宽问题
画形状的时间经常会用到点的坐标,这时原点O的位置就非常重要.在像素为1280*720的设备上画一条直线.代码如下所示: import android.app.Activity; import andr ...
- MONO 如何打包 .NET程序独立运行(winform篇)
.NET程序独立运行是指运行.NET的电脑上,不需要安装.NET框架. .NET程序集“独立运行”并非真正的独立,它是运行在mono运行时基础之上的.由于这个运行时可以独立存在,所以,我们不需要在目标 ...
- 【2017年新篇章】 .NET 面试题汇总(一)
开篇 本次给大家介绍的是我收集以及自己个人保存一些.NET面试题 简介 此次包含的不止是.NET知识,也包含少许前端知识以及.net面试时所涉及的种种考点,希望能给找工作的同学们哪怕一点点帮助. 古人 ...
- 利用jink调试程序,时间不准的解决办法
前几天,做工程,遇到了利用jlink的SWD的模式调试程序,定时器延时不准的问题,上网搜了好多,终于找到了问题所在,感谢万能的网友.时间不对是因为Keil的设置问题. 以下是转自网友: 一.先说说仿真 ...
- Java面试01|JVM相关
1.JVM内存查看与分析,编写内存泄露实例 堆区.栈区.方法区.本机内存都有可能内存溢出.在这里编写堆区内存溢出实例.如下(来自<深入理解Java虚拟机>一书. // -Xms20m -X ...
- 数据库中的T-sql语句 条件修改 高级查询
1.创建数据库:create database --数据库名,不能中文,不能数字开头,不能符号开头 2.删除数据库:drop database-- 数据库名 use student--使用数据库 3. ...
- Compare Version Numbers leetcode
Compare two version numbers version1 and version2.If version1 > version2 return 1, if version1 &l ...
- Insertion Sort List Leetcode
Sort a linked list using insertion sort. 这个题我巧妙的设置了一个临时头结点 class Solution { public: ListNode* insert ...
- ACM 组合数
组合数 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 找出从自然数1.2.... .n(0<n<10)中任取r(0<r<=n)个数的所有组合 ...
- 安装Eclipse(android)新建项目时遇到的问题
---恢复内容开始--- 解决方案: 我先删掉了新建的项目,重新建立项目时 将API都选成相同的API19:... 然后就成功了 ---恢复内容结束---