`
javatgo
  • 浏览: 1123389 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

阅读更多

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

赵锟

原文http://coolshell.cn/?p=1443

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

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

我们先编写一段程序

01.#include <string>
02.#include <iostream>
03.#include <sys/time.h>
04.
05.static long getcurrenttick()
06.{
07.long tick ;
08.struct timeval time_val;
09.gettimeofday(&time_val , NULL);
10.tick = time_val.tv_sec * 1000 + time_val.tv_usec / 1000 ;
11.return tick;
12.}
13.
14.int main( )
15.{
16.string the_base(1024 * 1024 * 10, 'x');
17.long begin = getcurrenttick();
18.for( int i = 0 ;i< 100 ;++i ) {
19.string the_copy = the_base ;
20.}
21.fprintf(stdout,"耗时[%d] \n",getcurrenttick() - begin );
22.}

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

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

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

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

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

1.string original = "hello";
2.char & ref = original[0];
3.string clone = original;
4.ref = 'y';

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

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

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

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

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

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

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

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

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

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

另外:上述例子是在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技术》一文

分享到:
评论

相关推荐

    C++17 使用 std::string_view避免字符串拷贝优化程序性能

    C++中std::string是日常Coding中经常使用的一个类,使用起来非常方便,但是也存在一些弊端。 如下代码,参数传递的过程发生了内存分配(Memory Allocation)和内存拷贝。 void fun(const std::string& s) { std::...

    c++11 std::move() 的使用

    std::move函数可以以非常简单的方式将左值引用转换为右值引用。...通过std::move,可以避免不必要的拷贝操作。 std::move是为性能而生。 std::move是将对象的状态或者所有权从一个对象转移到另一个... std::string str =

    利用C++实现从std::string类型到bool型的转换

    利用输入字符串流:std::istringstream 代码如下:bool b;std::string s = “true”;std::istringstream(s) &gt;&gt; std::boolalpha &gt;&gt;... 您可能感兴趣的文章:详解C++中String类模拟实现以及深拷贝浅拷贝自己模拟写C++中的St

    C++中string类的使用说明(保姆级说明)

    在C++中,`std::string` 类已经提供了丰富的方法来处理字符串,以下是 `std::string` 类的一些常用方法: 1. 构造函数: - `string()`: 默认构造函数,创建一个空字符串。 - `string(const char* s)`: 使用 C ...

    c++语言CSV文件分割解析

    使用c++开发的csv文件解析类。 namespace cpp { namespace str { /** 高性能的 csv 解析 */ class csv_parser { public: typedef std::pair, size_t &gt; string_t; typedef std::vector&lt;string_t &gt; fields_t; ...

    C++智能指针原理.pdf

    ⾸先看2个函数: //函数1 void remodel(std::string & str) { std::string * ps = new std::string(str); ... str = ps; return; } //函数2 void remodel(std::string &str) { std::string * ps = new std::string...

    C++调用Go方法的字符串传递问题及解决方案

    摘要:C++调用Go方法时,字符串参数的内存管理需要由Go侧进行深度值拷贝。 现象 在一个APP技术项目中,子进程按请求加载Go的ServiceModule,将需要拉起的ServiceModule信息传递给Go的Loader,存在C++调用Go方法,...

    C++中 String 类的常用方法.md

    `String` 类在 C++ 中是一个非常基础和常用的类,用于处理字符串。以下是一些 `string` 类的常用方法: 1. **构造函数** * `string()`: 创建一个空字符串。 * `string(const char* s)`: 使用 C 风格的字符串 `s...

    C++实现String类实例代码

    这是一道十分经典的面试题,可以短时间内考查学生对C++的掌握是否全面,答案要包括C++类的多数知识,保证编写的String类可以完成赋值、拷贝、定义变量等功能。 #include using namespace std; class String { ...

    c与c++面试题汇总(比较全)

    c与c++面试题汇总(比较全) 虽然有点小错误但是不影响阅读,此题仅供参考

    从string类的实现看C++类的四大函数(面试常见)

    一个C++类一般至少有四大函数,即构造函数、拷贝构造函数、析构函数和赋值函数,一般系统都会默认。但是往往系统默认的并不是我们所期望的,为此我们就有必要自己创造他们。在创造之前必须了解他们的作用和意义,...

    高质量C++编程指南 chm

    9.6 示例:类String的拷贝构造函数与赋值函数... 73 9.7 偷懒的办法处理拷贝构造函数与赋值函数... 75 9.8 如何在派生类中实现类的基本函数... 75 9.9 一些心得体会... 77 第10章 类的继承与组合... 78 ...

    动态Bitset源代码

    在C++的STL中实现由一个bitset类模板,其用法如下: std::bitset&lt;64&gt; bs; 也就是说,这个bs只能支持64位以内的位存储和操作;bs一旦定义就不能动态增长了。本资源附件中实现了一个动态Bitset,和标准bitset兼容。 /*...

    新手学习C++入门资料

    C++是C的超集,也可以说C是C++的子集,因为C先出现。按常理说,C++编译器能够编译任何C程序,但是C和C++还是有一些小差别。 例如C++增加了C不具有的关键字。这些关键字能作为函数和变量的标识符在C程序中使用,...

    C++日志类libglog使用

    附件是VS2010的工程,C++日志类,谷歌的东西,很好用,也很强大哦! glog简介 Google glog是一个基于程序级记录日志信息的c++库,编程使用方式与c++的stream操作类似,例: LOG(INFO) ; “LOG”宏为日志输出关键字...

    From C to C++

    // convert a string to uppercase! #include #define N 200 int main(){ char ms[N]; int i; printf("Input ms: "); gets(ms); for(i=0;ms[i];i++) if(ms[i]&gt;='a'&&ms[i]) ms[i]-='\x20'; puts(ms); ...

    fast_ber:C ++ 11 ASN.1 BER编码和解码库

    fast_ber 用C ++ 11编写的高性能ASN.1 BER编码和解码库介绍fast_ber...提供视图类以实现零拷贝解码模拟STL类型的接口,例如std :: string,std :: vector和std :: optional局限性没有循环数据结构大小和值约束未实现工

    LuaBind 源码 (Lua增强库)

    void print_string() { std::cout &lt;&lt; m_string ; } private: std::string m_string; }; 为了注册这个类到Lua环境,可以像下面这样写(假设你使用了名空间): module(L) [ class_("testclass") .def(constructor...

    C++智能指针:shared-ptr用法详解.pdf

    C++智能指针:shared_ptr⽤法详解 C++智能指针:shared_ptr⽤法详解 shared_ptr是C++11⾥的新特性,其包装了new操作符在堆上分配的动态对象。如: shared_ptr&lt;int&gt; sp1(new int(100)); //相当于 //int *sp1=new int...

    C++实现56dxw短信验证码WebService接口--

    -t 定义std:string到C++中的字符串转化规则, 当前例子采用UNIOCDE编码编译,请在wsmap.dat 中加上 xsd__string = | std::wstring | std::wstring* 这句话 -o 文件名,指定输出头文件 -n 名空间前缀 代替默认的ns ...

Global site tag (gtag.js) - Google Analytics