• 调试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 '00',
    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。

  • 相关阅读:
    bzoj2301: [HAOI2011]Problem b懵逼乌斯反演
    bzoj3504: [Cqoi2014]危桥 网络流
    bzoj1588: [HNOI2002]营业额统计 splay瞎写
    bzoj1008快速面
    洛谷1212手动枚举各种情况(缩代码成瘾)
    bzoj1968真·想sha法bi题
    bzoj3674同上(好短)
    bzoj3673可持久化线段树实现可持久化数组实现可持久化并查集(好长)
    uoj98未来程序改 纯暴力不要想了
    bzoj3680模拟退火
  • 原文地址:https://www.cnblogs.com/cobbliu/p/5841955.html
Copyright © 2020-2023  润新知