C++: auto_ptr + forward declaration?
Asked Answered
B

7

12

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?

Broody answered 23/12, 2009 at 10:23 Comment(2)
I used to get this problem when I declared an empty destructor (or didn't declare it at all) in the header file of class Cont. From your example up there you seem to be doing it correctly but just wanted to highlight this prob.Baxie
The d'tor is declared in the cpp, and I get the warning for the instantiation of the auto_ptr inside the class.Broody
B
13

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()
{
}
Bout answered 23/12, 2009 at 10:28 Comment(5)
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.Broody
That's very strange. Is that Visual C++?Bout
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.Bout
@Bout Just to be clear, defining the destructor is not always needed. The only important thing is that the definition of Inner should be available at the point Cont is destroyed. Also, there is no need of a virtual (in the) destructor.Harewood
@phaedrus: Yeap, except without a virtual destructor you still can bind a auto_ptr<Base> to Derived* and run into UB and not having the class definition at the point of object destruction is also UB and thus not required to be diagnosed by the compiler.Bout
B
4

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.

Broody answered 6/6, 2011 at 13:10 Comment(0)
A
3

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.

Arlyne answered 23/12, 2009 at 10:32 Comment(1)
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).Percyperdido
S
3

It seems to be ridiculous but I solved the same issue by adding #include <memory> to the Cont.h file.

Softfinned answered 5/12, 2012 at 12:45 Comment(0)
T
2

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.

Trim answered 15/6, 2011 at 8:30 Comment(0)
D
0

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

Deathlike answered 23/12, 2009 at 10:46 Comment(0)
H
0

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.

Hume answered 24/12, 2009 at 1:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.