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 }
...
You don’t declare an assignment operator for
Fooso if you use it the compiler will define one for you. The compiler generated one will use then copy assignment operator ofSharedPtrwhich, through a number of intermediate functions, callsdeleteon aFoo_impl.I can’t see your
Bar.cppso I can’t say where you might be copying aFoo.