What is the general guidance with using shared_ptr on interfaces that do not have virtual destructor?
Take the following code sample:
class IFoo
{
public:
virtual void M1() = 0;
};
class Foo : public IFoo
{
public:
void M1() {}
Foo() { std::cout << "Foo constructor\n";}
~Foo(){std::cout << "~Foo destructor\n";}
};
I think we all know that this is not safe:
{
IFoo *pFoo = new Foo();
delete pFoo;
}
Since IFoo is missing a virtual destructor, then ~Foo() will not be invoked in the above case.
So let's switch to using std::shared_ptr
{
std::shared_ptr<IFoo> spFoo(new Foo());
}
std::shared_ptr has a templated constructor that creates a "deleter". So when "spFoo" goes out of scope, the ~Foo destructor is properly invoked even though it's of type shared_ptr<IFoo>. But since my code targets older compilers, I have made use of Boost. But attempting this:
{
boost::shared_ptr<IFoo> spFoo(new Foo());
}
Generates a lot of scary warnings when compiling with -Wall.
In file included from /home/jselbie/boost_1_57_0/boost/checked_delete.hpp:15:0,
from /home/jselbie/boost_1_57_0/boost/smart_ptr/shared_ptr.hpp:26,
from /home/jselbie/boost_1_57_0/boost/shared_ptr.hpp:17,
from main.cpp:9:
/home/jselbie/boost_1_57_0/boost/core/checked_delete.hpp: In instantiation of ‘void boost::checked_delete(T*) [with T = Foo]’:
/home/jselbie/boost_1_57_0/boost/smart_ptr/detail/shared_count.hpp:134:38: required from ‘boost::detail::shared_count::shared_count(Y*) [with Y = Foo]’
/home/jselbie/boost_1_57_0/boost/smart_ptr/shared_ptr.hpp:271:47: required from ‘void boost::detail::sp_pointer_construct(boost::shared_ptr<X>*, Y*, boost::detail::shared_count&) [with T = IFoo; Y = Foo]’
/home/jselbie/boost_1_57_0/boost/smart_ptr/shared_ptr.hpp:349:58: required from ‘boost::shared_ptr<T>::shared_ptr(Y*) [with Y = Foo; T = IFoo]’
main.cpp:36:44: required from here
/home/jselbie/boost_1_57_0/boost/core/checked_delete.hpp:34:5: warning: deleting object of polymorphic class type ‘Foo’ which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
Now despite the warning about the non virtual destructor, the correct behavior of having ~Foo() invoked works. The interesting thing is that marking the destructor of the *derived* class (virtual ~Foo) makes the warning go away. It's like it's warning me that if I ever inherit from Foo, then I might run into issues - not of any immediate problems.
Should I never user shared_ptr with interface pointers that lack a virtual destructor? Always declare a virtual destructor? What is the guidance here?
jrs