views:

319

answers:

4

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 deletes 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?

+5  A: 

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()
{
}
sharptooth
I do that, but the warning points out that `Inner` needs to be defined at the line of the `auto_ptr` instantiation, inside the class.
shoosh
That's very strange. Is that Visual C++?
sharptooth
yes it is, MSVC2008
shoosh
The solution above is exactly how we do it in VS2k3, VS2k5 and VS2k8. Very-very strange. Perhaps you could turn on generation of a preprocessed file and examine it.
sharptooth
+2  A: 

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.

Pavel Radzivilovsky
Or `boost::scoped_ptr` which is closer except it even doesn't try to pretend your instances will be copyable. But then it still doesn't answer the question how one should go about using them with incomplete types (I think you'll need to define a destructor by which time the type is complete).
UncleBens
A: 

This question (deleting object with private destructor) and this question (how to write iscomplete template) may be help you.

Alexey Malistov
no, not really.
shoosh
A: 

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.

Brian Neal