AlexxanderX
AlexxanderX

Reputation: 276

Invalid application of 'sizeof' to incomplete type ( created classes)

I have next classes:

State.hpp

    ...

    class Engine;

    namespace window
    {

    class State
    { ... } }

WConsole.hpp

    ...

    class Engine;

    namespace window
    {

    class Console: public State
    { .. } }

WMesssage.hpp

    ...

    class Engine;

    namespace window
    {

    class Message: public State
    { ... } }

And all classes link to Engine class:

Engine.hpp

    ...

    namespace window 
    {
    class State;
    class Console;
    class Message;
    }

    class Engine
    {
        ...
        std::vector< std::unique_ptr<window::State> > m_windowObjects;
        std::unique_ptr<window::Console> m_consoleWindow;
        std::unique_ptr<window::Message> m_messageWindow;
        ...
    }

And in Engine.cpp I include the headers:

    #include "Engine.hpp"
    #include "WState.hpp"
    #include "WConsole.hpp"
    #include "WMessage.hpp"

If I try to compile I get this errors:

In file included from /usr/include/c++/4.8.2/memory:81:0,
                 from /usr/local/include/SFGUI/Signal.hpp:6,
                 from /usr/local/include/SFGUI/Object.hpp:4,
                 from /usr/local/include/SFGUI/Widget.hpp:4,
                 from /usr/local/include/SFGUI/Container.hpp:4,
                 from /usr/local/include/SFGUI/Bin.hpp:4,
                 from /usr/local/include/SFGUI/SFGUI.hpp:6,
                 from ./include/Handler.hpp:4,
                 from main.cpp:1:
/usr/include/c++/4.8.2/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = window::Console]':
/usr/include/c++/4.8.2/bits/unique_ptr.h:184:16:   required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = window::Console; _Dp = std::default_delete<window::Console>]'
./include/Engine.hpp:21:7:   required from here
/usr/include/c++/4.8.2/bits/unique_ptr.h:65:22: error: invalid application of 'sizeof' to incomplete type 'window::Console'
  static_assert(sizeof(_Tp)>0,
                      ^
/usr/include/c++/4.8.2/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = window::Message]':
/usr/include/c++/4.8.2/bits/unique_ptr.h:184:16:   required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = window::Message; _Dp = std::default_delete<window::Message>]'
./include/Engine.hpp:21:7:   required from here
/usr/include/c++/4.8.2/bits/unique_ptr.h:65:22: error: invalid application of 'sizeof' to incomplete type 'window::Message'

From what I see I don't get an error relating to window::State so mean that I introduced it in the right way, but why I get error relating to window::Console and window::Message? May affect that classes window::Console and window::Message are derivated from window::State?

Upvotes: 3

Views: 20869

Answers (3)

David Chelemen
David Chelemen

Reputation: 41

Short answer:

  • explicitly write a destructor of Engine
  • and move the definition of Engine to the cpp of engine.

Long answer:

  • Lets see the preprocessing ( all includes are replaced with the content of their header )
  • and a bit of compiling.

Imagine the following:

//B.h
class A;
class B
{
  std::unique_ptr<A> m_A;
  public:
  B();
};
//B.cpp
#include "B.h"
#include "A.h"
B::B()
  : m_A(new A())
{
}

lets see B.i result file after executing the following command (g++ -std=c++11 B.cpp -E B.i):

class A;
class B
{
  std::unique_ptr<A> m_A;

  public:
  B();
};
# 2 "B.cpp" 2
# 1 "A.h" 1
       

class A
{
public:
   int mInt;
   explicit A( int aInt = 0 )
      : mInt(aInt)
   {
   }
};
# 3 "B.cpp" 2
B::B()
  : m_A(new A())
{
}

Now comes the compiler part. According to cpp reference

If no user-declared prospective (since C++20)destructor is provided for a class type (struct, class, or union), the compiler will always declare a destructor as an inline public member of its class.

lets imagine the file with a declared destructor ( of course there will be declared copy constructor, assignment operator, but lets stick with destructor only )

class A;
class B
{
  std::unique_ptr<A> m_A;

  public:
  B();
  ~B(){} // <-------- FOCUS HERE
};
# 2 "B.cpp" 2
# 1 "A.h" 1
       

class A
{
public:
   int mInt;
   explicit A( int aInt = 0 )
      : mInt(aInt)
   {
   }
};
# 3 "B.cpp" 2
B::B()
  : m_A(new A())
{
}
  • Notice the destructor there, and imagine that thats the place where the destruction of our unique_ptr object or any object will be called.
  • Realise that in that place our unique_ptr has no idea how to destroy A, since A is only forward declared. A is only defined few lines later, but the compiler can not see that. In order to make it compilable, we must force the destructor definition, to be after the definition of A.
  • this is simple, create an explicit destructor, and make sure its defined in the cpp file.

Upvotes: 2

AlexxanderX
AlexxanderX

Reputation: 276

I modified to shared_ptr, but including the headers are still a option.

Here is the link for someone who may have same error here

Upvotes: 4

Alan Stokes
Alan Stokes

Reputation: 18964

The type argument to unique_ptr must be a complete type for a lot of use cases (see comments for the details); a forward declared class is incomplete. You must have a full definition of the class visible.

Upvotes: 2

Related Questions