为什么这个自定义指针类在执行过程中会突然崩溃,导致整个程序无法正常运行?

2026-04-16 19:394阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计584个文字,预计阅读时间需要3分钟。

为什么这个自定义指针类在执行过程中会突然崩溃,导致整个程序无法正常运行?

我正在实现一个特殊目的的句柄类。iHandle是一个必须实现接口,在我的实际代码中,它将包含运算符重载+*。但对于这个例子,我想保持简单,它只包含get函数。

我正在实现一个特殊目的句柄类.

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;} };

然后有一个句柄,用于进行空安全检查.

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,我希望能够使用句柄< B>的实例调用此函数.

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

但这为以下样本测试提供了一个段落错误.

struct A { virtual void talk() {printf("A\n");} }; struct B : public A { void talk() {printf("B\n");} }; 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; }

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

您可以点击此链接进行测试:
onlinegdb.com/BkAYuQZ3z

即使条件is_base_of< T,D> :: value为真,它也不会使(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"}; } }

本文共计584个文字,预计阅读时间需要3分钟。

为什么这个自定义指针类在执行过程中会突然崩溃,导致整个程序无法正常运行?

我正在实现一个特殊目的的句柄类。iHandle是一个必须实现接口,在我的实际代码中,它将包含运算符重载+*。但对于这个例子,我想保持简单,它只包含get函数。

我正在实现一个特殊目的句柄类.

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;} };

然后有一个句柄,用于进行空安全检查.

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,我希望能够使用句柄< B>的实例调用此函数.

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

但这为以下样本测试提供了一个段落错误.

struct A { virtual void talk() {printf("A\n");} }; struct B : public A { void talk() {printf("B\n");} }; 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; }

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

您可以点击此链接进行测试:
onlinegdb.com/BkAYuQZ3z

即使条件is_base_of< T,D> :: value为真,它也不会使(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"}; } }