C++ string类的隐式共享写时拷贝的实现及设计要点

字符串一种在程序中经常要使用到的数据结构,然而在C中却没有字符串这种类型。在C++中,为了方便字符串的使用,在STL中提供了一个string类。该类维护一个char指针,并封装和提供各种的字符串操作。

一、为什么要实现隐式公享写时拷贝
试想一下,如果我们要自己实现一个string类,最简单的方式是什么?就是让每一个string类的实例维护一个在内存中独立的字符数组,每个string对象各不相干。这样一个对象的任何变化都不会影响到其他的对象。这样做的好处就是处理简单,不易出错,但是这样做的缺点却是内存的使用量、程序的效率也低。
例如,对于如下的例子:
int swap(string &x, string &y)
{
    string tmp(x);
    x = y;
    y = tmp;
}
在上面的代码中,我们需要做的事情非常简单,只是想交换一下两个string对象的值而已。然而,如果我们采用上面所说的实现方式,一共在内存上进行了三次的用new来创建一个新的数组并复制数据,同时还会调用两次的delete[]。我们花了这么大的力气才完成了这样一个简单的动作。而隐式共享写时复制的内存管理策略却可以解决这样的问题。虽然C++11用&&运算符解决了上述问题,但是在程序中使用大量的string的副本,而不改变其值的情况还是不少的。例如string数组,删除一个元素后的移动操作。

二、隐式共享写时复制的实现思想
什么是隐式共享写时拷贝呢?就是当用一个string对象初始化另一个string对象或把一个string对象赋值给另一个string对象时,它们内部维护的指针其实指向了内存中的同一个字符数组,这就是隐式共享。

使用这种方法,上述的代码就不需要调用new来创建数组也不需要复制,也不会调用delete[](如果不是很明白也不要紧,看完实现代码和后自然就明白了)。然后两个指针指向同一个对象很容易引发错误,当其中一个对象执行析构函数释放掉其内部指针指向的内存时,另一个对象却对此完全不知情,可能会引用一个不存在的内存,从而让程序崩溃。所以为了方便资源的管理,我们引用智能指针的思想,为每个内存中的字符数组(用new创建,存在于堆中)添加一个引用计数used,表示有多少个对象引用这个块内存(即字符数组)。当一个对象析构时,它会把引用计数used减1,当used为0时,表示没有对象引用这块内存,从而把这块内存释放掉。当然由于used也要在对象中共享,所以它也是一个堆中的数据,每个对象有一个指向它的指针。

而当一个string对象需要改变它的值时,例如
string s1("abc");
string s2(s1);
string s3("edf");
s2 += s3;
此时,s1和s2指向了堆内存中的同一个字符数组,而当s2的值要改变时,因为如果直接在其指向的内存中修改,则会影响到对象s1,所以为了让s2的操作不影响到s1,s2会在重新new出一块内存,然后先把之前所引用的字符数组的数据复制到新的字符数组中,然后再把s3中的字符数据复制到新的字符数组中。这就是写时拷贝。注意,同时还要把之前指向的内存的引用计数减1(因为它指向了新的堆中的字符数组),并在堆中重新new一个块内存,用于保存新的引用计数,同时把新的字符数组的引用计数置为1。因为此时只有一个对象(就是改变值的对象)在使用这个内存。

三、代码实现及设计要点详解
说了这么多,还是来看看代码的实现吧,为了与标准C++的string类区别开来,这样采用第一个字母大写来表示自定义的字符串类String。

源代码可以点击下面的连接下载:

其头文件_stringv2.h如下:
#ifndef _STRINGV2_H_INCLUDED
#define _STRINGV2_H_INCLUDED
/***
String类的部分实现,采用的内存管理策略是:隐式共享,写时复制
实现方法:与智能指针的实现类似
***/
class String
{
    public:
        String();
        String(const String& s);
        String(const char *pc, size_t len);
        String(const char *pc);
        ~String();
        String& operator=(const String &s);
        String& operator=(const char *s);
        String& operator+=(const String &rhs);
        String& operator+=(co
  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值