说明:以下涉及的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;
}

最新文章

  1. SQL语句 多表基本操作
  2. Struts2 验证规则配置文件
  3. 阿里与腾讯“智慧城市”的O2O谁更强?(分享)
  4. 记一段使用node对mysql数据库做处理
  5. 关于Servlet的原理以及常用类
  6. 关于C# json转object时报错:XXXXXXXXXX需要标记“&quot;”,但找到“XX”。
  7. linux FILE 类型.
  8. IIS7 配置 PHP5.5
  9. MySQL生产库开发规范
  10. 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)
  11. Java读取打印机自定义纸张.
  12. Web/app端自动化测试对比
  13. entityframework单例模式泛型用法
  14. 微擎系统jssdk系统快速签名变量
  15. 加拿大抢先低调上架技嘉RTX 2060 显卡
  16. 国外源码精品-Android-PullToRefresh 简介与DEMO导入
  17. 第一章 spring起步
  18. Inside Triangle
  19. 20172319 《Java程序设计教程》 第9周学习总结
  20. T4模板批量生成代码文件

热门文章

  1. Android 获取控件滑动速度,速度跟踪器VelocityTracker;
  2. SpringBoot 六问
  3. 发送Http
  4. linux安装jdk8
  5. element-ui table 嵌套
  6. django-celery使用
  7. 富文本编辑器summerNote
  8. 003之MFCSocket异步编程(指针机制)
  9. Appium 学习一:环境搭建问题
  10. poj3273(二分)