IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

关于在“写时拷贝”发生的情况下直接操作string中内容出现的问题

Vimer 2010-06-24 09:48:28 累计浏览 3,419 次
本机暂存

注:本文是公司同事的一个分享,由于很有代表性,特分享在此,希望对大家有用。

上次welkin在处理一个豆瓣的cgi时遇到1个奇怪的问题,就是对一个string对象的修改引起了另一个string对象的同步修改。后来定位到原有,是因为有函数对string对象的buf内容直接进行了操作,破坏了“写时拷贝”的规则。下面这个例子说明了问题是如何产生的,已经如何避免:

int main()   
{   
    string str1 = \"abcd\";   
    string str2 = str1;   
    char *p1 = const_cast<char*>(str1.c_str());   
    p1[0] = \'o\';   
    //这里str1和str2同时被修改了   
    printf(\"%s %s\\n\", str1.c_str(), str2.c_str());   
    string str3 = \"abcd\";   
    string str4 = str3;   
    char *p2 = &(str3[0]);   
    p2[0] = \'o\';   
    //这里只有str3被修改,str4不变   
    printf(\"%s %s\\n\", str3.c_str(), str4.c_str());   
    return 0;   
}

上面的程序的运行结果如下:
obcd obcd
obcd abcd

str1和str2被同时改变这个比较好理解。因为str2的初值为str1,根据“写时拷贝”原则,在str2的值或者str1的值不发生改变的时候,2个对象实际上指向了同一块内存地址。

然而我们使用c_str方法取出了str1的buf首地址,且强制转换成了char*类型,这个强制转换的操作就是破坏C++标准的罪魁祸首了。它使得编译器无法获知通过指针p1对buf内容的修改操作而自动进行拷贝操作,结果就是str1和str2对象都被修改了。

而str3和str4为什么没有被同时修改呢。原因是指针p2的取值方式,它使用了[]操作符。C++标准认为,当你通过迭代器或[]获取到string的内部地址的时候,string并不知道你将是要读还是要写。这是它无法确定,为此,当你获取到内部引用后,为了避免不能捕获你的写操作,它在此时废止了“写时拷贝”技术!

实际上,将const char*强制转换为char*类型是问题的根本原因,他破坏了C++标准,我们应该尽量避免这么做。但现实是我们已经有很多接口这样实现了,这是一种典型的像C一样使用C++的行为。所以如果你遇到这种情况,记得使用[]操作符来获取string的第一个字符的地址,而不要使用c_str方法。

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 关于linux内存free的一些事情 (累计阅读 12,867)
  2. linux内核研究笔记(一)内存管理 – page介绍 (累计阅读 10,487)
  3. 如何学好C++语言 (累计阅读 10,448)
  4. Emacs配置C/C++-mode的代码智能提示和自动补全 (累计阅读 10,411)
  5. colortail,让 tail 命令绚丽起来 (累计阅读 10,259)
  6. 在C++中实现foreach循环,比for_each更简洁! (累计阅读 9,499)
  7. 几个内存相关面试题(c/c++) (累计阅读 9,445)
  8. 关于使用STL的红黑树map还是hashmap的问题 (累计阅读 8,875)
  9. 浅析C++多线程内存模型 (累计阅读 8,802)
  10. C++ 多线程编程总结 (累计阅读 8,097)