I'm concerned about using an incomplete type with a smart pointer and how the pointer is deleted. Is the following code safe? I don't think it would be, as main.cpp would generate Farm's default destructor which wouldn't see the complete type. To make it safe, I think I should create a non-inline destructor which sees the complete type. Is that correct?
Also is it the same if I used std::vector<Cow>
in Farm instead?
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 the destructor and it says error C2338: can't delete an incomplete type. I guess that answers my question.
I don't think your code should compile (and it doesn't in gcc)
std::unique_ptr<Cow>
uses std::default_delete<Cow>
, and std::default_delete<Cow>::operator()
should fail to instantiate for an incomplete type Cow
.
See also Is it true that a unique_ptr declaration, unlike a auto_ptr declaration, is well-defined when its template type is of an incomplete type?
So you're right: you need to ensure that default_delete<Cow>::operator()
is instantiated somewhere that the Cow
type is complete. Which means the destructor of Farm
needs to be defined in such a place.
I've just noticed that your subject says "smart pointer", while the question specifies unique_ptr
. The answer would be different for a shared_ptr
, since std::shared_ptr<Cow>::reset()
is a function template that captures the (static) type of the pointer passed to it and stores a deleter. So with shared_ptr
all you need is that the call to reset
has the complete type Cow
-- the location of the destructor doesn't matter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With