资料出处:
http://www.wuzesheng.com/?p=1686
众所周知,调试(Debugging)是每个程序员所要必备的基本的技术素养,尤其是对C/C++的程序员来说。对于在linux下用C/C++开发的朋友,相信对GDB不会陌生,当程序有bug或者是出现core dump的时候,GDB是我们最好的朋友。STL是C++相较于C而言,增加的非常强有力的工具,它从某种程度上把C/C++程序员从繁琐的基本数据结构中解放了出来。不过,STL虽然用起来十分方便,但是,用GDB调试过C/C++程序的朋友都有这样痛苦的经历,在GDB状态下,要知道某个STL对象(比如容器)中的数据内容,并不是那么直接、简单。本文的主要内容就是介绍STL中大家比较常用到的容器的基本组成,帮助大家能够在调试的时候更好的驾驭它们。
1. string
string是STL中最为常用的类型,它是模板类basic_string用char类型特化后的结果,下面我们来看一下string类型的基本组成:
01
typedef
basic_string<
char
>
string;
02
03
struct
_Rep_base
04
{
05
size_type
_M_length;
06
size_type
_M_capacity;
07
_Atomic_word
_M_refcount;
08
};
09
10
struct
_Alloc_hider
11
{
12
_CharT*
_M_p;
13
};
14
15
mutable
_Alloc_hider
_M_dataplus;
16
_M_data()
const
{
return
_M_dataplus._M_p;
}
17
_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()函数来查看。
2. vector
vector同样也是stl中最为常用类型,下面我们来看一下vector类型的基本组成:
1
struct
_Vector_impl
2
{
3
_Tp*
_M_start;
4
_Tp*
_M_finish;
5
_Tp*
_M_end_of_storage;
6
};
7
8
_Vector_impl
_M_impl;
vector本身很简单,就是一个动态数组。它只有一个数组成员_M_impl,用户可以通过_M_impl来查看vector内容的数据成员,具体包括动态数组的超始地址_M_impl._M_start,结束地址_M_impl._M_end_of_storage,数组内容的结束地址_M_impl._M_finish
3. list
list是STL中的双向链表结构,也是大家经常用来的,下面我们一起来看一下list的基本组成:
01
struct
_List_node_base
02
{
03
_List_node_base*
_M_next;
04
_List_node_base*
_M_prev;
05
};
06
07
template
<
typename
_Tp>
08
struct
_List_node
:
public
_List_node_base
09
{
10
_Tp
_M_data;
11
};
12
13
struct
_List_impl
14
{
15
_List_node_base
_M_node;
16
};