How to safely destroy a class with a smart pointer to an incomplete object type?

I am interested in using an incomplete type with a smart pointer and a way to delete a pointer. Is the following code safe? I do not think that would be so, since main.cpp would create a default farm destructor that would not see the full type. To make this safe, I think I should create a non-built-in destructor that sees the full type. It is right?

Same if I used std::vector<Cow> in a farm?

farm.h

 class Cow; struct Farm { Farm(); // ~Farm(); std::unique_ptr<Cow> cow; }; 

farm.cpp

 #include "cow.h" // cow now complete Farm::Farm() { cow.reset(new Cow); } // Farm::~Farm() {} 

main.cpp

 #include "farm.h" int main() { Farm farm; } 

Edit: I tried to compile with Visual Studio without a destructor, and it says error C2338: Cannot delete an incomplete type. I think this answers my question.

+7
c ++
source share
2 answers

I do not think your code should compile (and it is not in gcc)

std::unique_ptr<Cow> uses std::default_delete<Cow> , and std::default_delete<Cow>::operator() cannot create an instance for the incomplete type Cow .

See also. Is it true that a unique_ptr declaration, unlike an auto_ptr declaration, is well defined when its template type is an incomplete type?

So you are right: you need to make sure that default_delete<Cow>::operator() is created somewhere that the type Cow complete. This means that the Farm destructor must be defined in such a place.

I just noticed that your object says "smart pointer", and the question unique_ptr . The answer will be different for shared_ptr , since std::shared_ptr<Cow>::reset() is a function template that captures the (static) type of the pointer passed to it and saves the debiter. Thus, with shared_ptr all you need is that the reset call has the full Cow type - the location of the destructor does not matter.

+4
source share

The default destructor for Farm will include a descriptor for unique_ptr , which will include a destructor for Cow . This call will be made even if there is no definition at compile time. The linker is expected to link things after the fact.

+1
source share

All Articles