c++oding="utf-8" ?>
gdb默认不自动解引用智能指针,因其仅显示对象自身结构(如控制块地址),而非托管数据;需手动提取_m_ptr字段并强转解引用才能访问实际值。

直接看 std::shared_ptr 或 std::unique_ptr 的原始指针值,不能靠 print ptr 直接展开——GDB 默认只显示智能指针对象自身(如引用计数、控制块地址),不自动解引用其托管的资源。
为什么 print ptr 只显示 shared_ptr 结构,不显示内容?
GDB 读取的是 DWARF 调试信息,而标准库智能指针是模板类,其内部结构(如 std::_Sp_counted_base、_M_ptr 字段)在未加载 STL 扩展时不会被友好解析。你看到的类似 std::shared_ptr<int> (count 2, weak 0) 0x614c20</int>,那个 0x614c20 是控制块地址,不是你要的数据地址。
-
_M_ptr(实际指向数据的裸指针)通常是shared_ptr对象内存布局中的第一个成员,但 GDB 不会默认展示它 -
unique_ptr更简单,其_M_t._M_t._M_ptr(或类似路径)才是目标地址,但字段名随 libstdc++ 版本浮动 - 不加
-std=c++11或更高标准编译,调试信息可能缺失模板实例化细节,导致whatis返回不完整类型
怎么安全地打印 shared_ptr<int></int> 指向的值?
核心思路:先确认智能指针变量地址,再按内存偏移取出 _M_ptr,最后强转解引用。适用于 libstdc++(GCC 默认)。
- 用
print/x &ptr获取ptr变量自身的地址(比如是0x7fffffffe010) - 用
x/gx 0x7fffffffe010查看该地址起始的 8 字节(x86_64),这通常就是_M_ptr的值(即真实数据地址) - 假设输出是
0x614c20,则执行print *(int*)0x614c20即可拿到int值 - 更稳妥写法:
print *(int**)(&ptr)—— 把&ptr当作指向指针的指针来解,再解一次,但需确保类型匹配
调试 shared_ptr<myclass></myclass> 时怎么访问成员?
不能直接 print ptr->member;GDB 不支持重载操作符的自动调用。必须手动提取原始指针并强转为具体类型。
- 先用
x/gx &ptr得到_M_ptr地址(记为0x615a80) - 然后
print ((MyClass*)0x615a80)->data—— 注意括号顺序,避免类型转换失效 - 若不确定
MyClass定义是否被 GDB 加载,先运行whatis ptr看类型全名,再用ptype MyClass验证字段是否存在 - 对
unique_ptr,路径可能是((MyClass*)*((void**)(&uptr))),因为其内部常为_M_t._M_t._M_ptr,而_M_t是tuple,首元素即指针
有没有更省事的办法?
有,但依赖环境:用 rust-gdb 类思路不适用 C++,不过你可以启用 GDB 的 Python 扩展或加载 libstdc++ 自带的 pretty printer。
- 启动 GDB 前确保已安装
libstdc++6-<version>-dbg</version>(Ubuntu/Debian)或对应 debuginfo 包(RHEL/CentOS) - 在 GDB 中执行
source /usr/share/gcc-*/python/libstdcxx/v6/printers.py(路径依 GCC 版本而异) - 之后
print ptr就可能显示成std::shared_ptr<int> = {get() = 0x614c20, use_count() = 2}</int>,再补一句print *ptr.get()即可 - 缺点:pretty printer 对自定义分配器、复杂嵌套或旧版 libstdc++ 支持不稳定;一旦崩溃,回退到手动内存查看仍是基本功
真正麻烦的从来不是“怎么打出值”,而是确认你取出来的地址确实还有效——智能指针可能已被 move、reset,或控制块已销毁。调试时务必结合 info locals 和 backtrace 看生命周期上下文,别只盯着一个地址硬算。











