std::string的拷贝赋值研究
说明:以下涉及的std::string的源代码摘自4.8.2版本。
结论:std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址。
// std::string类定义
typedef basic_string<char> string;
template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string
{
private:
// _Alloc_hider是模板类basic_string内嵌struct
struct _Alloc_hider : _Alloc
{
// 唯一构造函数,
// 在构造时使用第一个参数__dat初始化_M_p
_Alloc_hider(_CharT* __dat, const _Alloc& __a)
: _Alloc(__a), _M_p(__dat)
{}
// _M_p为实际存储数据的地方
_CharT* _M_p; // The actual data.
};
private:
_CharT* _M_data() const
{ return _M_dataplus._M_p; }
// 浅拷贝,
// 这正是x2=x1后,两者数据地址相同的原因
_CharT* _M_data(_CharT* __p)
{ return (_M_dataplus._M_p = __p); }
_Rep* _M_rep() const
{
// 这里数组下标是“-1”
return &((reinterpret_cast<_Rep*>(_M_data()))[-1]);
}
// 维护引用计数
struct _Rep_base
{
size_type _M_length;
size_type _M_capacity;
_Atomic_word _M_refcount;
};
// _Rep是模板类basic_string内嵌struct
struct _Rep : _Rep_base
{
// The following storage is init'd to 0 by the linker,
// resulting (carefully) in an empty string with one reference.
// 空的std::string实际都指向了_S_empty_rep_storage,
// 因此它们的数据地址是相同的
static size_type _S_empty_rep_storage[];
static _Rep& _S_empty_rep()
{
void* __p = reinterpret_cast<void*>(&_S_empty_rep_storage);
return *reinterpret_cast<_Rep*>(__p);
}
_CharT* _M_grab(const _Alloc& __alloc1, const _Alloc& __alloc2)
{
return (!_M_is_leaked() && __alloc1 == __alloc2)
? _M_refcopy() : _M_clone(__alloc1);
}
_CharT* _M_refcopy() throw()
{
#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
__gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
return _M_refdata();
} // XXX MT
_CharT* _M_refdata() throw()
{ return reinterpret_cast<_CharT*>(this + 1); }
};
public:
static _Rep& _S_empty_rep()
{
return _Rep::_S_empty_rep();
}
// 不带参数的默认构造函数
// 测试环境_GLIBCXX_FULLY_DYNAMIC_STRING值为0,
// 因此只需要关注_S_empty_rep
basic_string()
#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
: _M_dataplus(_S_empty_rep()._M_refdata(), _Alloc())
{ }
#else
: _M_dataplus(_S_construct(size_type(), _CharT(), _Alloc()), _Alloc())
{ }
#endif
basic_string& assign(const basic_string& __str)
{
// 如果已经相同,则什么也不用做
if (_M_rep() != __str._M_rep())
{
const allocator_type __a = this->get_allocator();
_CharT* __tmp = __str._M_rep()->_M_grab(__a, __str.get_allocator());
_M_rep()->_M_dispose(__a);
_M_data(__tmp);
}
return *this;
}
#if __cplusplus >= 201103L
basic_string& assign(basic_string&& __str)
{
this->swap(__str);
return *this;
}
#endif // C++11
basic_string& operator=(const basic_string& __str)
{
return this->assign(__str);
}
private:
// mutable表明const成员函数会修改_M_dataplus
mutable _Alloc_hider _M_dataplus;
};
// 测试代码
// 编译命令:
// g++ -g -o x x.cpp -D_GLIBCXX_DEBUG
#include <stdio.h>
#include <string>
// 如果没有为结构X提供赋值函数,
// 则编译器生成默认的赋值函数
struct X {
std::string str;
};
int main() {
struct X x1, x2;
x1.str = "abc";
// X2指向的_S_empty_rep_storage
printf("%p, %p\n", x1.str.c_str(), x2.str.c_str());
// (gdb) p x1.str._M_dataplus._M_p
// (gdb) p x2.str._M_dataplus._M_p
// 拷贝赋值函数采用的是引用计数,
// 所以x1和x2的数据地址是相同的
x2 = x1;
printf("%p, %p\n", x1.str.c_str(), x2.str.c_str());
// 下面输出的x1和x2数据地址必然不同
x2.str = "123";
printf("%p, %p\n", x1.str.c_str(), x2.str.c_str());
return 0;
}
std::string的拷贝赋值研究的更多相关文章
- std::string的find问题研究
https://files-cdn.cnblogs.com/files/aquester/std之string的find问题研究.pdf 目录 目录 1 1. 前言 1 2. find字符串 1 3. ...
- QString, Std::string, char *相互转换
Qt 库中对字符串类型进行了封装,QString 类提供了所有字符串操作方法,给开发带来了便利. 由于第三方库的类型基本上都是标准的类型,即使用std::string或char *来表示字符 (串) ...
- 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)
标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...
- 使用 istreambuf_iterator 读取文件内容,赋值给 std::string
需要一个一个字符输入时考虑使用istreambuf_iterator 假设我们要把一个文本文件拷贝到一个字符串对象中.似乎可以用一种很有道理的方法完成: ifstream inputFile(&quo ...
- C++的std::string的“读时也拷贝”技术!
C++的std::string的读时也拷贝技术! 嘿嘿,你没有看错,我也没有写错,是读时也拷贝技术.什么?我的错,你之前听说写过时才拷贝,嗯,不错的确有这门技术,英文是Copy On Write,简写 ...
- std::string 赋值为nullptr引起程序崩溃
一个错误排查两天,std::string赋初值时最好为"", 如果赋初值为nullptr,因为std::string不能和nullptr作比较,所以后面用的时候会引起崩溃. 佩服我 ...
- 【转】标准C++类std::string的内存共享和Copy-On-Write技术
1. 概念 Scott Meyers在<More Effective C++>中举了个例子,不知你是否还记得?在你还在上学的时候,你的父母要你不要看电视,而去复习功 ...
- 源码阅读笔记 - 3 std::string 与 Short String Optimization
众所周知,大部分情况下,操作一个自动(栈)变量的速度是比操作一个堆上的值的速度快的.然而,栈数组的大小是在编译时确定的(不要说 C99 的VLA,那货的 sizeof 是运行时计算的),但是堆数组的大 ...
- c++ std::string 用法
std::string用法总结 在平常工作中经常用到了string类,本人记忆了不好用到了的时候经常要去查询.在网上摘抄一下总结一下,为以后的查询方便: string类的构造函数: string(co ...
随机推荐
- bootstrap-treeview初使用
<div id="tree">div> $(function () { function getTree() { var data = [{ text: &quo ...
- Titanic缺失数值处理 & 存活率预测
1. kaggle泰坦尼克数据titanic完整下载,原作者良心分享 https://download.csdn.net/download/lansui7312/9936840 2. 缺失值处理 # ...
- [INet] WebSocket 数据收发的详细过程
WebSocket 和 HTTP 相似,只是一个应用层协议,对下层透明,所以不涉及 TCP/IP. 由于浏览器支持了 WebSocket,所以在用 JS 写客户端的时候,是无需考虑数据的编码解码的. ...
- Reboot-less node fencing in Oracle Clusterware 11g Release 2
在进行一次RAC的高可用性测试时,当private网卡的网线被拔掉之后,没有出现传说中的有一个节点被CRS强制重启,取而代之的是node2上面的ASM实例和RDBMS实例被关闭:当网线被重新插上时,n ...
- Linux Oracle安装
lsnrctl status // 查看linux系统oracle的监听状态lsnrctl start // 启动linux系统oracle的监听状态 sqlplus /nolog // 连接 ...
- react-native 新手爬坑经历(unable to load script from assets 和could not connect to development server.)
按照https://reactnative.cn/docs/0.51/getting-started.html教程新建的项目 react-native init AwesomeProject cd A ...
- jstl标准标签库 常用标签
JSTL(JSP Standard Tag Library)标准标签库: 1, 核心标签(最常用, 最重要的) 表达式控制标签 out 输出常量 value---直接赋值 输出变量 default-- ...
- centos7源码安装heartbeat可能出现的错误以及解决办法
问题:ipmilan_command.c: In function 'setup_ipmi_conn':ipmilan_command.c:283:2: error: 'sel_alloc_selec ...
- 用归并排序或树状数组求逆序对数量 poj2299
题目链接:https://vjudge.net/problem/POJ-2299 推荐讲解树状数组的博客:https://blog.csdn.net/int64ago/article/details/ ...
- error link 2019 waveout
winmm.lib的影响 在做音频播放的时候使用到了win系统音频函数waveout; 但是报错: error link 2019 无法解析外部符号:waveoutGetnumDevice /clos ...