調試std::string


    首先需要了解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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM