std::string内部规则(引用计数vsmemcpy)?

探讨GCC5.3.0及devtool5.3.1中引用计数规则变动,分析新版GCC取消引用计数,采用深拷贝替代浅拷贝的原因,及其对性能与安全的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 写在前面

该规则适用于新版c++,至于多新,我也没闹明白,gcc 5.3.0是适用以下规则的。

2. 规则

    规则1:gcc5.3.0 不等同于devtool5.3.1,devtool貌似是为了版本兼容而生的。并不是真正将gcc升级。

    规则2:新版gcc(原则上高于4.8.5,但实际只测试过5.3.0)已经完全取消了引用计数规则,当做string赋值时,永远都是深拷贝字符串。

    以下都是分析了,上述两点是结论,时间紧任务重的小伙伴们可以先走了。

3:诉求

    在复制大字符串的时候,内部的memcpy非常耗时,我们明明知道我们不会改动复制之后的字符串。但系统为了安全,帮我们深拷贝了一份。我们就在想呀,如果用浅copy,也同样能达到效果,而且也不用memcpy。这不一举两得么?

4:老gcc实现

    这个时候,老gcc知道了我们的诉求,这还不简单,应用最时髦的COW技术(copy on write)即可解决。做法如下,当我们copy一个字符串时引用加1,当我们析构一个字符串时引用-1,这样不就成了么?

4.1 修改

    那问题来了,如果我要修改一个字符串,如果浅copy两个不都全改了么?老版gcc很好的解决了这个问题,如果当你使用了operator[]函数的时候,就说明你有改动该字符串的意向,就会重新帮你复制一个字符串出来。云云,反正大意就是,当你想改的时候才会帮你做深copy,平时全是浅copy。

5. 新gcc实现

5.1 老gcc问题

    那么问题来了,我如果写了如下代码该咋整?    

#include <iostream>

using namespace std;

int main() {

    string str("hello world);
    {
        string str2(str.c_str(), str.size());
        (void*) str2.c_str();
    }
    return 0;
}

这样str2因为他的构造string到底是一个char*还是一个string。

我们的本意是str,str2共用一个字符串,引用计数--即可。但因为传递的是指针,所以str,str2都包涵了字符串的指针,引用计数都为1,当str2析构的时候,str的内部指针就悬垂了。

大部门新手都会出现这样的问题。那么为了避免该问题。和该问题确实也是string类的一个bug。那么就:

5.2 改动

很简单的解决版本,所有的string copy操作都改为深copy即可。

string str1 = str;
string str2(str);

string str3;
str3.assign(str);

这样虽然牺牲了效率,但赢得了安全,可真是自损800,伤敌800呀。

再说另外一个事情,就是devtool 5.3.1不是gcc5.3.0 为啥呢。

6. devtools

自始至终gcc没有权威推出过5.3.1版本。但如果你安装的devtools的话,你gcc --version你会发现你的gcc版本是5.3.1的。

因为如下代码跟正版的gcc 5.3.0差距过大,所以我推测,devtools的实现方式是 新gcc的特性+老gcc的内核导致可以让老gcc兼容新gcc。

研究后发现推测成立,且5.3.1是red hat的版本。

7. 总结

该问题只有我们这种青黄不接的程序员才会出现。因为我们用的老gcc,新gcc的改动又不知道,极其容易掉到坑里。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值