C++的std::string的“读时也拷贝”技术!

C++的std::string的读时也拷贝技术!

嘿嘿,你没有看错,我也没有写错,是读时也拷贝技术。什么?我的错,你之前听说写过时才拷贝,嗯,不错的确有这门技术,英文是Copy On Write,简写就是COW,非常’牛’!那么我们就来看看这个’牛’技术的效果吧。

我们先编写一段程序

#include <string>
#include <iostream>
#include <sys/time.h>
static long getcurrenttick()
{
    long tick ;
    struct timeval time_val;
    gettimeofday(&time_val , NULL);
    tick = time_val.tv_sec * 1000 + time_val.tv_usec / 1000 ;
    return tick;
}
int main( )
{
    string the_base(1024 * 1024 * 10, 'x');
    long begin =  getcurrenttick();
    for( int i = 0 ;i< 100 ;++i ) {
       string the_copy = the_base ;
    }
    fprintf(stdout,"耗时[%d] \n",getcurrenttick() - begin );
}

嗯,一个非常大的字符串,有10M字节的x,并且执行了100此拷贝。编译执行它,非常快,在我的虚拟机甚至不要1个毫秒。

现在我们来对这个string加点料!

int main(void) {
    string the_base(1024 * 1024 * 10, 'x');
    long begin =  getcurrenttick();
    for (int i = 0; i < 100; i++) {
        string the_copy = the_base;
        the_copy[0] = 'y';
    }
    fprintf(stdout,"耗时[%d] \n",getcurrenttick() - begin );
}

现在我们再编译并执行这断程序,居然需要4~5秒!哇!非常美妙的写时才拷贝技术,性能和功能的完美统一。

我们再来看看另外一种情况!

string original = "hello";
char & ref = original[0];
string clone = original;
ref = 'y';

我们生成了一个string,并保留了它首字符的引用,然后复制这个string,修改string中的首字符。因为写操作只是直接的修改了内存中的指定位置,这个string就根本不能感知到有写发生,如果写时才拷贝是不成熟的,那么我们将同时会修改original和clone两个string。那岂不是灾难性的结果?幸好上述问题不会发生。clone的值肯定是没有被修改的。看来COW就是非常的牛!

以上都证明了我们的COW技术非常牛!

有太阳就有黑暗,这句说是不是有点耳熟?

int main(void) {
    string the_base(1024 * 1024 * 10, 'x');
    fprintf(stdout,"the_base's first char is [%c]\n",the_base[0] );
    long begin =  getcurrenttick();
    for (int i = 0; i < 100; i++) {
        string the_copy = the_base;
    }
    fprintf(stdout,"耗时[%d] \n",getcurrenttick() - begin );
}

啊,居然也是4~5秒!你可能在想,我只是做了一个读,没有写嘛,这到底是怎么回事?难道还有读时也拷贝的技术!。

不错,为了避免了你通过[]操作符获取string内部指针而直接修改字符串的内容,在你使用了the_base[0]后,这个字符串的写时才拷贝技术就失效了。

C++标准的确就是这样的,C++标准认为,当你通过迭代器或[]获取到string的内部地址的时候,string并不知道你将是要读还是要写。这是它无法确定,为此,当你获取到内部引用后,为了避免不能捕获你的写操作,它在此时废止了写时才拷贝技术!

这样看来我们在使用COW的时候,一定要注意,如果你不需要对string的内部进行修改,那你就千万不要使用通过[]操作符和迭代器去获取字符串的内部地址引用,如果你一定要这么做,那么你就必须要付出代价。当然,string还提供了一些使迭代器和引用失效的方法。比如说push_back,等, 你在使用[]之后再使用迭代器之后,引用就有可能失效了。那么你又回到了COW的世界!比如下面的一个例子

int main( )
{
    struct timeval time_val;
    string the_base(1024 * 1024 * 10, 'x');
    long begin = 0 ;
    fprintf(stdout,"the_base's first char is [%c]\n",the_base[0] );
    the_base.push_back('y');
    begin = getcurrenttick();
    for( int i = 0 ;i< 100 ;++i ) {
        string the_copy = the_base ;
    }
    fprintf(stdout,"耗时[%d] \n",getcurrenttick() - begin );
}

一切又恢复了正常!如果对[]返回引用进行了操作又会发生情况呢,有兴趣的朋友可以试试!结果非常令人惊讶。

另外:上述例子是在linux环境下编译的,使用STL是GNU的STL。windows上我用的是vs2003,但是非常明显vs2003一点都不支持COW。

这篇文章出自http://ridiculousfish.com/blog/archives/2009/09/17/i-didnt-order-that-so-why-is-it-on-my-bill-episode-2/ 这里,我使用了它的例子。但是我重新自己组织了内容。

编写这篇文章的同时,我还参考了耗子的《标准C++类string的Copy-On-Write技术》一文

转自:http://coolshell.cn/articles/1443.html

原创文章,作者:s19930811,如若转载,请注明出处:http://www.178linux.com/2430

(0)
s19930811s19930811
上一篇 2015-04-03
下一篇 2015-04-03

相关推荐

  • openssl基础应用

    参考http://www.178linux.com/2704 http://www.williamlong.info/archives/837.html 一、前言 什么是openssl?讲openssl之前我们先了解下什么是ssl?ssl是secure socket layer的简称,其使用对称加密解密,非对称加密解密(公钥加密解密),单向加密解密结合证书实…

    Linux干货 2015-09-27
  • linux小小小入门。

      ❀用户登录:     ❤root用户 这是一个特殊的管理账户,也被称为超级账户,root已经接近完整的系统控制。但是对系统的损害有非常广泛的能力。(一般情况下不会登录root)     ❤普通用户 权限有限,损害能力较小。 ❀终端terminal:     ❤设备终端 键盘,鼠标,显示器     &#x…

    Linux干货 2018-03-26
  • 正则表达式基础

    一、正则表达式: 元字符是用来阐释字符表达式意义的字符,简言之,就是用来描述字符的字符。 正则表达式RE(Regular Expression)是由一串字符和元字符构成的字符串。 正则表达式的主要功能是文本查询和字符串操作,它可以匹配文本的一个字符或字符集合。实际上正则表达式完成了数据的过滤,将不满足正则表达式定义的数据拒绝掉,剩下与正则表达式匹配的数据。 …

    Linux干货 2017-06-04
  • Linux文件的权限与解析

    一,文件的基本权限: 通常,你使用ls -l 命令,就会看到这样的行:   让我们解析一下这些字段代表的意思: -rw-r–r–. 1 root root 1018 Nov 6 2016 usb_modeswitch.conf 文件类型权限  硬链接数 文件所有者 文件所属组 文件容量  文件最后被修改时…

    2017-07-30
  • 萧田国给你五个2017GOPS北京站的参会理由!

    2017年7月28日,GOPS全球运维大会即将开幕,发起人萧田国将在主会场发表题为《运维如何延续自己的职业生涯》演讲,参加第七届北京站您会有哪些收益? 收益一: 【长达半天时间的培训式演讲】让您系统性掌握顶级互联网自动化运维体系 收益二: 【腾讯智能运维】传奇背后的细节,听了才知道 收益三: 与Facebook、Twitter、BATJ等运维大咖【面对面深度…

    Linux干货 2017-07-24
  • 博客

       这是我的第一篇博客!   平时学习中,总会遇到或大或小的问题,以及一些新的感悟,在当时能够十分清晰记得,但过一些时日,便发现又忘记了。以前十分明白的东西,又变得有些模糊,甚至完全忘记。因此特别需要记录下来,方便日后的查阅或分享给其他遇到类似问题的朋友。    如果以后忘记的某些知识,这时候,翻开以往博客…

    Linux干货 2017-07-11