Search code examples
c++polymorphismfactory

c++ shared_ptr in polymorphism without virtual destructor


A typical factory design pattern require the base class to declare virtual destructor, but this can be actually avoided using shared_ptr.

#include <iostream>
#include <memory>
#include <cstdio>

using namespace std;

class Dog {
  public:
  ~Dog() { cout << "dog destroyed\n"; }
};

class Yellowdog : public Dog {
  public:
  ~Yellowdog() { cout << "Yellow dog destroyed.\n"; }
};

class DogFactory {
  public:
  static shared_ptr<Dog> createYellowdog() { 
    return shared_ptr<Yellowdog>(new Yellowdog()); 
  }
};

int main(int argc, char *argv[]) {

  auto ptr = DogFactory::createYellowdog();
  cout << ptr.use_count() << endl;

  return 0;
}

In this case the output is yellowdog destroyed followed by dog destroyed. But why? Why using shared_ptr can omit the virtual keyword before ~Dog?


Solution

  • This is happening because shared_ptr stores type-erased deleter in the control block, which is created when the first shared_ptr is created. In your case shared_ptr is created for yellow dog, and deleter is to call yellow-dog destructor.

    When you copy (or copy-construct) one shared_ptr to another, they share the same control block, and new shared ptr is going to call deleter from the original one - the one which will call yellowdog destructor.

    However, it doesn't really make the class polymorphic and suitable for factory implementation - any other non-virtual function in the class will be called based on static type of shared_ptr, and you do not want this in polymorphic classes.