日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

std::string的拷贝赋值研究

發布時間:2023/12/15 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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;
}

轉載于:https://www.cnblogs.com/aquester/p/10531183.html

總結

以上是生活随笔為你收集整理的std::string的拷贝赋值研究的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。