zoukankan      html  css  js  c++  java
  • 调试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。

  • 相关阅读:
    一百零二、SAP中ALV事件之十五,让ALV表格自动求和
    一百零一、SAP中ALV事件之十四,让ALV表格自动排序
    一百、SAP中ALV事件之十三,给ALV的自定义按钮添加事件
    九十九、SAP中ALV事件之十二,给ALV的标题栏添加图片
    九十八、SAP中ALV事件之十一,查看图片
    九十七、SAP中ALV事件之十,通过REUSE_ALV_COMMENTARY_WRITE函数来显示ALV的标题
    九十六、SAP中ALV事件之九,显示功能按钮栏中显示ALV加强工具栏
    九十五、SAP中查看自定义包的所有模块,对象,函数主,事务等
    二十、JavaScript之对象
    十九、JavaScript之数组
  • 原文地址:https://www.cnblogs.com/cobbliu/p/5841955.html
Copyright © 2011-2022 走看看