I have a class like this:
class Inner;
class Cont
{
public:
Cont();
virtual ~Cont();
private:
Inner* m_inner;
};
in the .cpp, the constructor creates an instance of Inner
with new
and the destructor delete
s it. This is working pretty well.
Now I want to change this code to use auto_ptr
so I write:
class Inner;
class Cont
{
public:
Cont();
virtual ~Cont();
private:
std::auto_ptr<Inner> m_inner;
};
Now, the constructor initialized the auto_ptr
and the destructor does nothing.
But it doesn't work. the problem seem to arise when I'm instantiating this class. I get this warning:
warning C4150: deletion of pointer to
incomplete type 'Inner'; no
destructor called
Well, this is obviously very bad and I understand why it happens, The compiler doesn't know about the d'tor of Inner
when instantiating the template of auto_ptr<Inner>
So my question: Is there a way to use auto_ptr
with a forward declaration like I did in the version that uses just plain pointers?
Having to #include
every class I declare a pointer to is a huge hassle and at times, just impossible. How is this problem usually handled?
You need to include the header defining class Inner
into the file where Cont::~Cont()
implementation is located. This way you still have a forward declaration in teh header defining class Cont
and the compiler sees class Inner
definition and can call the destructor.
//Cont.h
class Inner; // is defined in Inner.h
class Cont
{
virtual ~Cont();
std::auto_ptr<Inner> m_inner;
};
// Cont.cpp
#include <Cont.h>
#include <Inner.h>
Cont::~Cont()
{
}
Turns out the problem occurs only when I make the c'tor inline. If I put the c'tor in the cpp, after the decleration of Inner
everything's ok.
You may consider boost::shared_ptr() instead. It has no practical disadvantages instead of performance, and is much more friendly to forward declarations:
boost::shared_ptr<class NeverHeardNameBefore> ptr;
is okay, without extra declarations above.
shared_ptr does more than auto_ptr, such as reference counting, but it should not harm if you don't need it.
It seems to be ridiculous but I solved the same issue by adding #include <memory>
to the Cont.h file.
The forward declaration in the header is ok if you implement the destructor in the cont.cpp file and you include inner.h, as others pointed out.
The problem could be in the use of Cont. In each cpp that uses (and destroys) Cont you have to include cont.h AND inner.h. That solved the problem in my case.
This question (deleting object with private destructor) and this question (how to write iscomplete template) may be help you.
You aren't technically supposed to instantiate standard library templates with incomplete types, although I know of no implementation where this won't work. In practice, Sharptooth's answer is what I'd recommend also.
There really wasn't anything wrong with using a naked pointer for your impl pointer, as long as you call delete on it in your destructor. You should probably also implement or disable the copy constructor and assignment operator.