C++: string copy-on-write
https://blog.csdn.net/haoel/article/details/24058
https://www.cnblogs.com/promise6522/archive/2012/03/22/2412686.html
https://stackoverflow.com/questions/6245235/confusion-about-copy-on-write-and-shared-ptr
https://stackoverflow.com/questions/628938/what-is-copy-on-write
https://en.wikipedia.org/wiki/Copy-on-write
string COW
1、
string str1 = "hello world";
printf ("\tstr1's address: %x\n", str1.c_str() );
输出str1的地址
std::cout << "str1's address: " << std::hex << str1.c_str() << std::endl;
输出str1的内容
std::cout 的类型 std::ostream 的基类 std::basic_ostream 有一个这样的 operator<< 重载:basic_ostream& operator<<( const void* value );
这个重载可以输出指针的值(也就是地址)。----------------------------------------然而 std::basic_ostream 还有几个非成员 operator<< 重载:template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,
const CharT* s );
template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,
const char* s );
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const signed char* s );
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const unsigned char* s );
这些函数负责输出由 char* 或其他字符类型的指针表示的字符串。----------------------------------------所以由于 char* (或者 charT*)比 void* 更加特化(不知道特化是什么没关系,以后会学到),在 【cout << p】且 p 的类型是 char* 的情况下,负责输出字符串的 operator<< 重载会被调用。
2、原始版本
// string
class CMyString
{
public:
CMyString(const char* initValue = "");
~CMyString();
CMyString(const CMyString& rhs);
CMyString& operator= (const CMyString& rhs);
private:
char* data;
};
// String
CMyString::CMyString(const char* initValue)
{
if (NULL == initValue)
{
data = new char[1];
*data = '\0';
}
else
{
data = new char[strlen(initValue) + 1];
strcpy(data, initValue);
}
}
CMyString::~CMyString()
{
delete []data;
}
CMyString::CMyString(const CMyString& rhs)
{
data = new char[strlen(rhs.data) + 1];
strcpy(data, rhs.data);
}
/*
CMyString& CMyString::operator= (const CMyString &rhs)
{
if (this != &rhs)
{
delete [] data;
data = NULL;
data = new char[strlen(rhs.data) + 1];
strcpy(data, rhs.data);
}
return *this;
}
*/
CMyString& CMyString::operator= (const CMyString &rhs)
{
// 考虑异常安全
if (this != &rhs)
{
CMyString tmpString(rhs);
char* pTemp = tmpString.data;
tmpString.data = data;
data = pTemp;
}
return *this;
}
3、引用计数
创建一个带引用计数的String类并不困难,但需要注意一些细节,所以我们将略述这样一个类的大部分常用成员函数的实现。然而,在开始之前,认识到“我们需要一个地方来存储这个计数值”是很重要的。这个地方不能在String对象内部,因为需要的是每个String值一个引用计数值,而不是每个String对象一个引用计数。这意味着String值和引用计数间是一一对应的关系,所以我们将创建一个类来保存引用计数及其跟踪的值。我们叫这个类StringValue,又因为它唯一的用处就是帮助我们实现String类,所以我们将它嵌套在String类的私有区内。另外,为了便于Sting的所有成员函数读取其数据区,我们将StringValue申明为struct。需要知道的是:将一个struct内嵌在类的私有区内,能便于这个类的所有成员访问这个结构,但阻止了其它任何人对它的访问(当然,除了友元)。
基本设计是这样的:
class String
{
public:
String(const char* initValue = "");
~String();
String(const String& rhs);
String& operator= (const String& rhs);
const char& operator[] (int index) const;
char& operator[] (int index);
private:
struct StringValue
{
int refCount;
char *data;
StringValue(const char *initValue);
~StringValue();
};
StringValue* value;
};
String::StringValue::StringValue(const char *initValue)
: refCount(1)
{
data = new char[strlen(initValue) + 1];
strcpy(data, initValue);
}
String::StringValue::~StringValue()
{
delete [] data;
}
这是其所有的一切,很清楚,这不足以实现带引用计数的String类。一则,没有拷贝构造函数和赋值运算;二则,没有提供对refCount的操作。别担心,少掉的功能将由String类提供。StringValue的主要目的是提供一个空间将一个特别的值和共享此值的对象的数目联系起来。StringValue给了我们这个,这就足够了。
String::String(const char* initValue)
: value(new StringValue(initValue))
{
}
String::~String()
{
if (0 == --value->refCount)
{
delete value;
}
}
String::String(const String& rhs)
: value(rhs.value)
{
++value->refCount;
}
String& String::operator= (const String &rhs)
{
if (value == rhs.value)
{
return *this;
}
if (0 == --value->refCount)
{
delete value;
}
value = rhs.value;
++value->refCount;
return *this;
}
const char& String::operator[] (int index) const
{
return value->data[index];
}
char& String::operator[] (int index)
{
// if we're sharing a value with other String objects,
// break off a separate copy of the value for ourselves
if (value->refCount > 1)
{
--value->refCount; // decrement current value's refCount
value = new StringValue(value->data); // make a copy of the value for ourselves
}
// return a reference to a character inside our
// unshared StringValue object
return value->data[index];
}
我们希望以不同的方式处理读和写。简单的读操作,可以用与const的operator[]类似的方式实现,而写操作必须用完全不同的方式来实现。
当我们修改一个String对象的值时,必须小心防止修改了与它共享相同StringValue对象的其它String对象的值。不幸的是,C++编译器没有办法告诉我们一个特定的operator[]是用作读的还是写的,所以我们必须保守地假设“所有”调用非const operator[]的行为都是为了写操作。(Proxy类可以帮助我们区分读还是写,见Item M30。)
为了安全地实现非const的operator[],我们必须确保没有其它String对象在共享这个可能被修改的StringValue对象。简而言之,当我们返回StringValue对象中的一个字符的引用时,必须确保这个StringValue的引用计数是1。
编译器根据调用成员函数的对象的const属性来选择此成员函数的const和非const版本,而不考虑调用时的环境。
C++: string copy-on-write的更多相关文章
- string::copy
size_t copy (char* s, size_t len, size_t pos = 0) const;功能:把string的pos位置开始的len字节copy到s注意:s的最后要手动添加字符 ...
- std::string::copy函数
size_t copy (char* s, size_t len, size_t pos = 0) const;
- string中c_str()、data()、copy(p,n)函数的用法
标准库的string类提供了3个成员函数来从一个string得到c类型的字符数组:c_str().data().copy(p,n). 1. c_str():生成一个const char*指针,指向以空 ...
- C#入门篇6-3:字符串操作 string的ToString() Split()和Copy()方法
//ToString()方法 public static void OutPut() { //字符型转换 转为字符串 Console.WriteLine(.ToString("n" ...
- iOS 浅谈:深.浅拷贝与copy.strong
深.浅拷贝 copy mutableCopy NSString NSString *string = @"汉斯哈哈哈"; // 没有产生新对象 NSString *copyStri ...
- Copy 与MutableCopy的区别
NSString *string = @"origion"; NSString *stringCopy = [string copy]; NSMutableString *stri ...
- Objective -C学习笔记 之copy(复制)
//自定义类对象实现copy需要遵守copy协议(否则程序崩溃),实现必须实现的协议方法,里面的代码就决定了你的copy是深是浅 #import <Foundation/Foundation.h ...
- retain copy(浅复制) mutablecopy (深复制)
http://blog.csdn.net/xdrt81y/article/details/24331103 口诀: 1浅3深 NSArray copy (浅) 返回NSArray NSArra ...
- 转载一篇关于ios copy的文章
由于原文创作时间较早,一些内容不实用了,我对其进行了加工,去掉了一部分内容,添加了一点注释. 原文连接 http://www.cnblogs.com/ydhliphonedev/archive/201 ...
- iOS - OC Copy 拷贝
前言 copy:需要先实现 NSCopying 协议,创建的是不可变副本. mutableCopy:需要实现 NSMutableCopying 协议,创建的是可变副本. 浅拷贝:指针拷贝,源对象和副本 ...
随机推荐
- 如何省略.jsx文件名
在webpack.config.js文件夹中module.exports中添加: resolve:{ extensions:[".js", ".jsx", &q ...
- layui中下拉框问题
<div class="layui-form-item"> <label class="layui-form-label">上级栏目:& ...
- 非常实用的css
.clearfix:after {content: "";display: block;visibility: hidden;height: 0;clear: both;} .cl ...
- 骑马修栅栏 Riding the Fences
题目背景 Farmer John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. 题目描述 John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经过一个栅栏.你必须编一个 ...
- css translate/rotate 空间坐标轴
参考:https://www.cnblogs.com/zhangnan35/p/10709876.html https://www.cnblogs.com/zyrblog/p/11142624.htm ...
- Peasy.NET学习之并发问题处理
Peasy.net之并发处理 BusinessServiceBase是ServiceBase的自定义实现,提供了额外的独特功能 首先,创建一个业务服务,该业务服务必须继承BusinessService ...
- Windows的ODBC配置指南: MySQL, PostgreSQL, DB2, Oracle
MySQL- 官网: https://dev.mysql.com/downloads/connector/odbc/- 安装: * msi格式, 直接安装即可 * zip格式, 解压缩, 命令行(管理 ...
- Ubuntu 18.04 切换使用Python3
我安装的Ubuntu 默认的python是2.7.5 python -V 我参考网上照到的文章,如果需要默认python为 python3 python命令默认是 python 3 sudo cp / ...
- mysql 学习之1 mysql的基本语法
转载一位csdn中 乍得12138前辈的 转载:https://blog.csdn.net/qq_26200347/article/details/79781882
- leetcode -有效的字母异位词 python&C++
C++解题代码: class Solutiion { public: bool isAnagram(string s, string t) { ](); int n = s.length(); int ...