说明:以下涉及的std::string的源代码摘自4.8.2版本。 结论:std::string的拷贝复制是基于引用计数的浅拷贝,因此它们指向相同的数据地址。 // std::string类定义 typedef basic_string string; template 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(&_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 #include // 如果没有为结构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; }