首先需要了解std::string的實現原理
string是STL中最為常用的類型,它是模板類basic_string用char類型特化后的結果,下面我們來看一下string類型的基本組成:
typedef basic_string<char> string; struct _Rep_base { size_type _M_length; size_type _M_capacity; _Atomic_word _M_refcount; }; struct _Alloc_hider { _CharT* _M_p; }; mutable _Alloc_hider _M_dataplus; _M_data() const { return _M_dataplus._M_p; } _Rep* _M_rep() const { return &((reinterpret_cast<_rep *> (_M_data()))[-1]); }
string只有一個成員_M_dataplus。但是這里需要注意的是,string類在實現的時候用了比較巧的方法,在_M_dataplus._M_p中保存了用戶的數據,在_M_dataplus._M_p的第一個元素前面的位置,保存了string類本身所需要的一些信息rep。這樣做的好處,一方面不增加string類的額外開銷,另一方面可以保證用戶在調試器(GDB)中用_M_dataplus._M_p查看數據內容的時候,不受干擾。用戶可以通過reinterpret_cast<_rep *> (_M_data()))[-1])來查看rep相關的信息,也可以調用_M_rep()函數來查看。
(gdb) p &base $3 = (const std::locale::string *) 0x7fffffffe9d0
拿到string的_Rep結構
(gdb) p *((const std::locale::string* )0x7fffffffe9d0)->_M_rep() $9 = { <std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep_base> = { _M_length = 10485760, _M_capacity = 10489799, _M_refcount = 0 }, members of std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep: static _S_max_size = 4611686018427387897, static _S_terminal = 0 '\000', static _S_empty_rep_storage = {0, 0, 0, 0} }
如果進程已經不存在了,無法調用->_M_rep(),會報錯:
(gdb) p (('google::protobuf::internal::LogMessage::string' *) 0x2e560500)->_M_rep() You can't do that without a process to debug.
我還遇到過一種情況,在多線程環境中,調用->_M_rep()會有如下報錯:
(gdb) p this->mRequest->data_->_M_rep() [Switching to Thread 0x51931940 (LWP 10454)] Breakpoint 1, XXXX::XXXX::XXXXX::Run (this=0xa522700) at build/release64/XXXX/XXXXXX/XXXXXX/xxx.cpp:71 71 in build/release64/XXXX/XXXXXX/XXXXXX/xxx.cpp
The program stopped in another thread while making a function call from GDB. Evaluation of the expression containing the function
這是因為gdb在執行->_M_rep()函數時發生了線程切換,或者有其他線程同樣執行到了break點,這種情況的一個解決方法是調整gdb的scheduler-locking策略(http://ftp.gnu.org/old-gnu/Manuals/gdb/html_node/gdb_39.html#SEC40):
(gdb) show scheduler-locking Mode for locking scheduler during execution is "step". (gdb) set scheduler-locking on (gdb) c Continuing.
如果沒法通過->_M_rep()函數找到_Rep結構,那么只能通過下面的方法找:
1)找到_M_p結構:
(gdb) p (('google::protobuf::internal::LogMessage::string' *) 0x2e560500)->_M_dataplus $11 = { <std::allocator<char>> = { <__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, members of std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Alloc_hider: _M_p = 0x7f9b39706018 "" }
2)找_M_p指針前面的三個double word:
(gdb) x/32dg 0x7f9b39706018 - 32 0x7f9b39705ff8: -6052009417173884928 524288 0x7f9b39706008: 528327 4294967295 0x7f9b39706018: 0 0
上圖中,524288就是_Rep的_M_length,528327就是_Rep的_M_capacity,4294967295就是_Rep的_M_refcount,這兒實際上是-1。