Shared_ptr destructor, copy and incomplete type

I have a header file foo.h like this (unrelated things are omitted):

 #pragma once #include <memory> class Bar; struct Foo { std::shared_ptr<Bar> getBar(); std::shared_ptr<const Bar> getBar() const { return const_cast<Foo*>(this)->getBar(); } }; 

The non-constant overload of getBar() implemented in the .cpp file, which also sees the full definition of Bar .

When foo.h included from another file (which does not see the definition of Bar ), VS 2010 gives me a warning similar to this:

 warning C4150: deletion of pointer to incomplete type 'Bar'; no destructor called 

when overloading const getBar() (or actually on something deep in the standard library created from this overload).

My question is whether this warning can be ignored.

As I look at it, getBar() const calls two member functions std::shared_ptr<Bar> : the conversion constructor and the destructor.

 // converting constructor template <class Y> std::shared_ptr<const Bar>::shared_ptr(std::shared_ptr<Y> &&r) 

This is used to initialize the return value of getBar() const from the return value of getBar() . This does not contain any preconditions (C ++ 11 27.2.2.1 Β§20-22), which requires Y ( Bar in my case).

 // destructor std::shared_ptr<const Bar>::~shared_ptr() 

27.2.2.2 Β§ 1 states that when a common pointer is destroyed, there are no side effects.

I understand why I get a warning - the destructor code should also take care of the situation where delete should be called by the stored pointer, and this code will really delete the incomplete type. But, as I see it, it can never be achieved in my situation, so getBar() const is safe.

Am I right, or did I miss a call or something that could make getBar() const actually remove the incomplete type?

+5
c ++ c ++ 11 shared-ptr incomplete-type
source share
2 answers

I can not find any justification for the warning. I also cannot reproduce the warning using clang / libC ++.

In general, given a shared_ptr<Bar> , without seeing the shared_ptr<Bar> construct that accepts Bar* and, optionally, a debiter, there is no certainty that if ~Bar() ever . It is impossible to find out what remainder was stored in shared_ptr<Bar> , and given the unknown deleter d , which is stored in shared_ptr<Bar> , along the side Bar* (say p ), there is no requirement d(p) call ~Bar() .

For example, your Bar may not have a destructor available:

 class Bar { ~Bar(); }; 

And your Foo::getBar() can be implemented as follows:

 std::shared_ptr<Bar> Foo::getBar() { // purposefully leak the Bar because you can't call ~Bar() return std::shared_ptr<Bar>(new Bar, [](Bar*){}); } 

Unable to recognize the compiler without seeing foo.cpp.

This warning looks like a compiler error for me, or perhaps an error in the implementation of std::shared_ptr .

Can you ignore the warning? I dont know. It seems to me that you are dealing with an implementation error, and therefore an error may mean that the warning is real. But assuming a completely appropriate implementation, I don’t see Bar being the full type in the code you showed.

+7
source share

Not; warning cannot be safely ignored. Your code creates a shared_ptr object. The shared_ptr constructor is a template that creates and saves a debiter. By adding the code to create shared_ptr in your header, you started the premature instantiation of the template constructor.

The deleteter trick used by shared_ptr allows you to declare them before the class definition, but they should still see the full type before you use them for the first time. Your code does not have a guarantee to call the destructor Bar, ever. Even worse, today it may even work, but it can be a time bomb, which is very difficult to debug an error in your code.

The problem has nothing to do with the contents of the pointer in the code. Just the fact that you have code that creates a generic pointer that does not see the full definition of Bar is enough.

Easy to fix. Just put this code in your implementation file after the full declaration of Bar.

Edit: The warning given by g ++ matches this situation, but the code does not. For now, I'm going to leave this answer until I have time to investigate (or someone else finds out why g ++ gives this warning).

+1
source share

All Articles