The compiler shoots itself in the foot when trying to optimise/inline my trivially looking but non-trivial dtor, what am I doing wrong?

StackOverflow https://stackoverflow.com/questions/11268178

Question

I have this shared pimpl*. It forward declares the implementation object and has a custom-implemented shared pointer object to implement the pimpl idiom (again, with sharing semantics). Condensed, it looks like this:

Foo.h

#include "SharedPtr.h"

class Foo_impl;
class FooFactory;
class Foo {
  friend class FooFactory;
  private:
    SharedPtr<Foo_impl> pimpl;
    Foo(SharedPtr<Foo_impl>);
  public:
    ~Foo();
};
struct FooFactory {
  Foo build() const;
};

Foo.cpp

#include "Foo.h"

Foo FooFactory::build() const {
  return Foo(SharedPtr<Foo_impl>(new Foo_impl(/*...*/)));
}
Foo::Foo(SharedPtr<Foo_impl> pimpl)
  : pimpl(pimpl) {
}
Foo::~Foo() {
}

Now, (I think) the compiler gets really smart when compiling Bar.cpp (which uses Foo objects and other SharedPtr objects) and complains:

SharedPtr.h: In member function ‘void Deallocator<T>::operator()(T*) const [with T = Foo_impl]’:
SharedPtr.h:54:   instantiated from ‘void SharedPtr<T, Delete>::drop() [with T = Foo_impl, Delete = Deallocator<Foo_impl>]’
SharedPtr.h:68:   instantiated from ‘SharedPtr<T, Delete>::~SharedPtr() [with T = Foo_impl, Delete = Deallocator<Foo_impl>]’
SharedPtr.h:44: warning: possible problem detected in invocation of delete operator:
SharedPtr.h:42: warning: ‘t’ has incomplete type
Foo.h:29: warning: forward declaration of ‘struct Foo_impl’
SharedPtr.h:44: note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined.

Who could possibly be calling ~SharedPtr<Foo_impl> other than Foo and FooFactory? Where does that come from and how can I fix it?

Note: Making ~Foo virtual doesn't help, which is even more puzzling to me.


* The fact that the impl is shared is irrelevant here, I just want to prevent the typical "please define a copy-ctor/assignment method" comments. It is fully intentional that the pimpl pointer is shared.


Edit: The SharedPtr interface:

 33     template <typename T> struct Deallocator {
 34       private:
 35         bool doDelete; // not const to be def. assignable
 36       public:
 38         Deallocator(bool doDelete = true) : doDelete(doDelete) {}
 39         bool willDelete() const {
 40           return doDelete;
 41         }
 42         void operator()(T* t) const {
 43           if (doDelete)
 44             delete t;
 45         }
 46     };
 47
 48     template <typename T, typename Delete = Deallocator<T> > class SharedPtr : private SharedPtrBase {
 49       private:
 50         Delete del;
 51         T* ptr;
 52         void drop() {
 53           if (ptr && shouldDelete()) {
 54             del(ptr);
 55           }
 56           ptr = NULL;
 57           leave();
 58         }
 59       public:
 60         // SharedPtr(p,false) will not delete the pointer! Useful for Stackobjects!
 61         explicit SharedPtr(T* ptr = NULL, Delete del = Delete())
 62           : SharedPtrBase(), del(del), ptr(ptr) {
 63         }
 64         SharedPtr(SharedPtr const& from)
 65           : SharedPtrBase(from), del(from.del), ptr(from.ptr) {
 66         }
 67         ~SharedPtr() {
 68           drop();
 69         }
 70         SharedPtr& operator=(SharedPtr const& from) {
 71           if (&from != this) {
 72             drop();
 73             del = from.del;
 74             ptr = from.ptr;
 75             join(&from);
 76           }
 77           return *this;
 78         }
 79         SharedPtr& operator=(T* from) {
 80           return *this = SharedPtr(from,del);
 81         }
 ...
Was it helpful?

Solution

You don't declare an assignment operator for Foo so if you use it the compiler will define one for you. The compiler generated one will use then copy assignment operator of SharedPtr which, through a number of intermediate functions, calls delete on a Foo_impl.

I can't see your Bar.cpp so I can't say where you might be copying a Foo.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top