Not default destructor causes incomplete type error

Viewed 850

This example shows strange behavior of compilers (msvc14, gcc, clang), but I did't find explanation.

When we implement pipml idiom and use forward declaration we need to consider that unique_ptr has own specific behavior with incomplete types. This cases was mentioned here and here.

But when we move definition of forwarded class to another header file and include headers in one place later with usage of client class, compilers become insane - in some special cases of destructor declaration they says about incomplete type.

Here is an minimal example. If uncomment "#define CASE_2" or "#define CASE_3" and try to build it, there will be compilation error.

file foo.h

#ifndef FOO_H
#define FOO_H

class Foo{};

#endif // FOO_H

file base.h

#ifndef BASE_H
#define BASE_H

#include <memory>

//#define CASE_1
//#define CASE_2
//#define CASE_3

class Foo;

class Base
{
public:

#if defined(CASE_1)
    ~Base() = default; // OK!
#elif defined(CASE_2)
    ~Base() {}; // error: invalid application of 'sizeof' to incomplete type 'Foo'
#elif defined(CASE_3)
    ~Base(); // error: invalid application of 'sizeof' to incomplete type 'Foo'
#endif

    // OK!

private:
    std::unique_ptr<Foo> m_foo;
};

#endif // BASE_H

file base.cpp

#include "base.h"

#if defined(CASE_3)
Base::~Base()
{
}
#endif

file main.cpp

#include "foo.h"  // No matter order of this includes
#include "base.h" //

int main()
{
    Base b;
}
2 Answers
Related