Incomplete type for std::vector

廉价感情. 提交于 2020-01-01 04:34:06

问题


The GCC compiler complains (see below) when I try the following. class Face needs to be incomplete because it contains pointer to class Element which similarly contains pointer to class Face. In other words, there is a circular dependency among classes. How can I fix it?

error: invalid application of ‘sizeof’ to incomplete type ‘Face’

class Face; // needs to be incomplete

class Element
{
    std::vector < std::unique_ptr <Face> > face;
};

class Face
{
    std::vector < std::unique_ptr <Element> > elm;
};

回答1:


One way to fix this is to declare the destructors and constructors of Element and Face but not define them in the header. Then you need to define them in cpp files.

(More technical details can be found in the answers to my question there: Is std::unique_ptr<T> required to know the full definition of T?)

The source of the problem is that the destructor of unique_ptr needs to call delete (by default) therefore it needs to know the definition of the type (to have it's size). But if the destructor of Element and Face is generated automatically, then it will be inlined by default: the code using Element and Face instances will be forced to know the size of both types so that their destructors can call unique_ptr destructor which can call delete with the type associated to the pointer.

The solution I gave will make sure the construction and destruction of the unique_ptr are defiend in a separate cpp. They will not be inlined but they are still callable by the code using Element and Face. The destructor code of the unique_ptrs will be in the cpp where the destructors of Element and Face are defined, so in these cpp the definition of both will be needed.

To take your example:

//header
class Face; // needs to be incomplete

class Element
{
public:
    Element(); // don't define it here
    ~Element(); // don't define it here
private:
    std::vector < std::unique_ptr <Face> > face;
};

class Face
{
public:
    Face(); // don't define it here
    ~Face(); // don't define it here
private:
    std::vector < std::unique_ptr <Element> > elm;
};

// cpp 
#include "header"
// if you want the default impl (C++11)
Element::Element() = default; 
Element::~Element() = default; 

Face::Face() = default; 
Face::~Face() = default; 

In case they are in different header/cpp pair, it's still the same solution. However you have to do more forward declare and the cpp files defining the construction/destruction have to include all the necessary headers:

//element.h
class Face; // needs to be incomplete

class Element
{
public:
    Element(); // don't define it here
    ~Element(); // don't define it here
private:
    std::vector < std::unique_ptr <Face> > face;
};

////////////////////////////////////////////////////////////
// face.h
class Element; // needs to be incomplete

class Face
{
public:
    Face(); // don't define it here
    ~Face(); // don't define it here
private:
    std::vector < std::unique_ptr <Element> > elm;
};

////////////////////////////////////////////////////////////
// element.cpp 
#include "element.h"
#include "face.h" // necessary to allow the unique_ptr destructor to call delete

// if you want the default impl (C++11)
Element::Element() = default; 
Element::~Element() = default; 

////////////////////////////////////////////////////////////
// face.cpp 
#include "element.h" // necessary to allow the unique_ptr destructor to call delete
#include "face.h" 

// if you want the default impl (C++11)
Face::Face() = default; 
Face::~Face() = default; 


来源:https://stackoverflow.com/questions/23984061/incomplete-type-for-stdvector

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!