为什么此自定义指针类会崩溃?

Why does this custom pointer class crash?

本文关键字:崩溃 指针 自定义 为什么      更新时间:2023-10-16

我正在实现一个特殊用途的句柄类。

ihandle是所有句柄都必须实现的接口,在我的实际代码中,它将具有运算符重载->*。但是对于这个例子,我想保持简单,它只有get功能。

template <typename T>
class ihandle {
public:
virtual T* get();
};

一种可能的实现是ptr,它只是一个原始指针。

template <typename T>
class ptr : public ihandle<T>
{
T* t;
public:
ptr(T* t = nullptr) : t(t) {}
T* get(){return t;}
};

然后是用于进行空安全检查的handle

template <typename T>
class handle
{
public:
ihandle<T>* h;
T* get(){return h->get();}
handle(ihandle<T>* h = nullptr) : h(h) {}
template <typename D>
handle(handle<D>& hd)
: h((ihandle<T>*)hd.h)
{
static_assert(is_base_of<T, D>::value, "error");
}
};

有这个构造函数,用于能够从继承类的句柄强制转换为基类的句柄。

template <typename D>
handle(handle<D>& hd)
: h((ihandle<T>*)hd.h)
{
static_assert(is_base_of<T, D>::value, "error");
}

例如,如果B继承自A,我希望能够使用handle<B>的实例调用此函数。

void foo(handle<A> ha) {
// do something
}

但这为以下示例测试提供了段错误。

struct A {
virtual void talk() {printf("An");}
};
struct B : public A {
void talk() {printf("Bn");}
};
int main()
{
handle<B> hb(new ptr<B>(new B));
//hb.get()->talk(); // if uncomment, no segfault
handle<A> ha = hb;
ha.get()->talk(); // segfault here
return 0;
}

我怀疑问题可能出在handle(handle<D>& hd)构造函数中,但我不明白发生了什么。

您可以通过单击此链接对其进行测试: https://onlinegdb.com/BkAYuQZ3z

即使条件is_base_of<T, D>::value为 true,也不会使(ihandle<T>*) hd.h强制转换有效,因为ptr<B>ihandle<A>类型不相关。我想这是绝对应该避免C型铸造的一个例子。要安全地执行转换,您可以使用带有检查dynamic_cast

: h(dynamic_cast<ihandle<T>*>(hd.h))
{
if(hd.h && !h)
{
throw ::std::runtime_error{"pointers are not related"};
}
}

问:您使用什么编译器/链接器? 当我使用 VS-2017 编译您的东西时,我收到链接器错误。当我像在您的主要测试中包含 hb 声明时,它期望一个 B->get(),

handle<B> hb(new ptr<B>(new B));

..但是当我为虚拟方法 ihandle.get() 提供一些默认实现时,就像这样。

template <typename T>
class ihandle {
public:
virtual T* get() { return NULL; }
};

返回 NULL.. 我的链接器错误消失了......并且没有崩溃。您测试报告 B 或 B B。

希望我能帮上忙。感谢您的代码!我正在学习C++自动取款机,上面的例子是一个很好的研究。