shared_ptr找不到虚方法

Ste*_*ve 5 c++ shared-ptr

我有一个abstact基类,在它的构造函数中调用一个虚方法.在传递一个shared_ptr基类之后,找不到该方法的实现.

class a 
{
 public:
   a() { fill(); }
 protected:
   virtual void fill() = 0;
}

class b : public a
{
public:
   b() : a();
protected:
   virtual void fill() { // do something }
} 
....

shared_ptr<a> sptr = shared_ptr<a> ( new b()): // error happens here on runtime
Run Code Online (Sandbox Code Playgroud)

执行此操作时,我得到一个SIGABRT,因为它试图执行 virtual void fill() = 0;

Rei*_*ica 7

您无法从构造函数中调用纯虚函数.在构造函数运行时,该对象被认为是正在构造的类型,而不是任何派生类型.这意味着虚拟调度在正在构造的类型上"停止".

这意味着fill()从构造函数调用a将尝试调用a::fill(),无论该a子对象可以属于哪个派生类.这当然失败了,因为该功能没有实现.


另外,正如@KerrekSB指出的那样,你的类需要一个虚拟析构函数.否则,你会得到未定义的行为,如果你曾经delete一个b通过指针实例a(这是很可能的时候shared_ptr<a>参与).

更新显然,shared_ptr能够使用默认的删除器属性来解决虚拟析构函数的必要性,因此您的类在技术上可以没有.但是,如果没有虚拟析构函数,您的类依赖于std::shared_ptr仅在s中进行管理; 如果你改变了那一点设计,你就会遇到麻烦(而且不会立即显而易见).因此,无论如何,我建议使用虚拟析构函数.

  • 在这种情况下,共享指针*不会*尝试通过指向"a"的指针删除.如果用`b*`初始化它,那么它将使用`std :: default_deleter <b>`并删除正确的类型,无论是否有虚拟析构函数. (2认同)
  • @MikeSeymour:非常高兴知道.我没有意识到这是必需的.特别值得注意的是,*不能与`unique_ptr`一起工作,你必须明确地提供自己的删除器. (2认同)