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 ...
随机推荐
- redis持久化 (rdb
RDB(快照持久化) RDB(redis database),可以理解为快照/内存快照,RDB持久化过程是将当前进程中的数据生成快照存储到硬盘中 触发机制RDB持久化的触发机制分为两种,手动触发和自动 ...
- 说下spring生命周期
面试官:说下spring生命周期 程序员:不会 那你先回去等消息吧 Bean实现了BeanNameAware,Spring会将Bean的ID透传给setBeanName java.后端开发.程 ...
- 使用Jenkins部署Python项目
廖大使用Fabric部署的.我使用Jenkins试试部署过程.虽然说是用python项目部署测试的,但其他项目也是同理的. 参考Jenkins+Python部署完整版,不过安装方式不同. 安装tomc ...
- 【HDFS API编程】开发环境搭建
使用HDFS API的方式来操作HDFS文件系统 IDEA Java 使用Maven来管理项目 先打开IDEA,New Project 创建GAV然后next 默认使用的有idea内置的Maven,可 ...
- leetcode94
class Solution { public: vector<int> V; void inOrder(TreeNode* node) { if (node != NULL) { if ...
- c# JSON格式转对象
using Newtonsoft.Json; List<string> ChapterIdList = JsonConvert.DeserializeObject<List<s ...
- HTML - input(转)
自: http://www.runoob.com 标签定义及使用说明 <input> 标签规定了用户可以在其中输入数据的输入字段. <input> 元素在 <form&g ...
- SQL(ORACLE)
查询数据库编码: select * from sys.nls_database_parameters;select * from sys.nls_session_parameters; replace ...
- 【原】 The Linux Command Line- pwd,cd,ls,file,less
pwd - print name of current working directory. cd - change directory ls - list directory contents fi ...
- MQ队列堵塞无法读取经验总结
问题现象: 1号发生本地来帐队列无法读取消息的问题,导致来帐报文均无法正常处理. 原因分析: 应用系统没有修改或上包,昨天交易和消息读取还是一切正常,mbfe的状态也是正常,mq的状态正常,以上正常可 ...