c++containmentmutual-recursion

Avoid cyclic dependencies - need for mutual containment


In my GUI system, the main building block is Container class, which can be drawn (= is drawable). However, Container itself is a 'kind of a table' - it contains cells.

Cell class serves for layouting. The number of cells a container has is defined by number of rows and columns.Cell objects are not visible.

And here's the problem. Cell objects cannot be drawn - they contain Container objects, which are drawn by the rules defined in the Cell object (alignment, padding, etc..) when calling cell.draw().

I know this can be easily resolved by using raw pointers to avoid the circular dependency created here, but I wanted to use smart pointers, if possible. However, according to error I'm getting, it's obvious smart pointers have to know the size of the object, unlike raw pointers.

Unique_ptr error

/usr/include/c++/4.8/bits/unique_ptr.h:65:22: error: invalid application of ‘sizeof’ to incomplete type ‘Container’
  static_assert(sizeof(_Tp)>0,

Container.hpp

#include <Cell.hpp> // Causes circular dependency
class Cell; // Causes error: invalid application of ‘sizeof’

class Container
{
// ...
private:
    std::vector<std::unique_ptr<Cell>> cells;
// ...
}

Cell.hpp

#include <Container.hpp> //Causes circular dependency
class Container; // Causes error: invalid application of ‘sizeof’
class Cell
{
// ...
private:
    std::vector<std::unique_prt<Container>> subcontainers;
// ...
}

Is there a nice way how to solve the situation using smart pointers (maybe by redesigning the whole problem solution), or do I have to use raw pointers here?


Solution

  • std::unique_ptr works on forward declared types, but it needs to know the full type for invoking the deleter.

    This will bite you if your class uses a compiler-generated destructor. You can get rid of the problem by defining a (possibly empty) custom destructor for the class out-of-line in a source file where the full type definition for the type held by the unique_ptr is visible.

    Refer to this answer for the gory details.