我有一个应用程序,在这个应用程序中,我经历了一些罕见的由于nullptr析出的分段故障。应用程序中的指针值遵循一个非常标准的生命周期。
当我对一个核心进行事后分析时,如果能知道指针之所以有一个nullptr值,是因为它刚刚被未初始化,但没有被设置为一个实际的实例(即在上述步骤1和2之间),还是因为它之前已经被释放了(在上述步骤4之后),将会很有帮助。为了帮助分析,我想使用魔法指针值来初始化和释放后的对象。我想到的是hexspeak的值,如 0xCAFEBABE
和 0xDEADBEEF
分别用于步骤1和步骤4。
我有多种类型的指针,我想用于此。我发现,对于任何给定的类型,我都可以使用显式转码来初始化它。下面是一个最小的例子。
#include <iostream>
using namespace std;
class A {
public:
A(int a) : _a{a} {};
int _a;
};
int
main(int argc, char* argv[])
{
A *a = reinterpret_cast<A*>(0xCAFEBABE);
cout << a->_a << endl;
return 0;
}
这就是我想要的: 当我运行这个的时候,它就会崩溃,而当我打印这个值的时候 a
在调试器中,它打印出 0x00000000cafebabe
.
然而,为每个指针类型指定reinterpret_cast,每次初始化一次,每次销毁后一次,会变得很繁琐。有没有更有效的方法来完成这个任务?
更新
有几个人加了评论,建议我用智能指针管理这些指针。我很欣赏这个反馈的意图,但是这个建议并不适用于这种情况,因为这并不是管理这些对象寿命的bug。一般来说,我在这个应用程序中的类的实例都是由智能指针管理的。在这次崩溃的特殊情况下,指针是针对OpenSSL对象的,这些对象是用SSL_new构造的,用SSL_free释放的。但这不是重点:当连接创建时,它们被正确地构造,当连接消失时,它们被正确地释放。实例不应该存在于该时间范围之外。当我的应用程序的一部分试图使用这些非实时实例之一进行写入时,错误就会出现。为了帮助追踪这个问题,我想知道写是发生在连接建立之前还是连接消失之后的对象上。这就是魔法指针值的作用。
你可以使用一个函数模板来消除一点繁琐。
template <typename Object>
Object* get_pointer()
{
return reinterpret_cast<Object*>(0xCAFEBABE);
}
template <typename Object>
Object* get_pointer(Object* /*unused*/)
{
return get_pointer<Object>();
}
并使用它作为。
A* a = get_pointer(a);
或者...
A* a = get_pointer<A>();