繁体   English   中英

当无法尽可能优雅地进行前向声明时,如何解决循环类依赖关系?

[英]How can I resolve a circular class dependency when forward declaration is not possible as elegantly as possible?

我有这样的事情:

struct v_with_holder {
    // bunch of fields
    holder h; // does not name a type
};

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

我最近才添加了此特定变体。 其他所有代码都具有标准的,已经定义的数据类型和类,因此可以复制构造它们,并且代码库可以这样编写(例如,调用ss.push_back(v) )。

问题是,直到我声明holder ,我才能声明v_with_holder ,反之亦然。 前瞻性声明class holder; 给出field 'h' has incomplete type 'holder'

我以为我可以使用unique_ptr

class holder;
struct v_with_holder {
    // bunch of fields
    std::unique_ptr<holder> ph;
    holder& h;
    v_with_holder(); 
    ~v_with_holder();
};

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

v_with_holder::v_with_holder() : ph(new holder), h(*ph) { }
v_with_holder::~v_with_holder() { }

但是,现在的问题是v_with_holder不再是可复制构造的:

holder h1, h2;
v_with_holder x;
x.h = h2;
h1.ss.push_back(x); // error: use of deleted function 'v_with_holder::v_with_holder(const v_with_holder&)'

现在看来,我唯一的求助方法就是定义复制构造函数,这些复制构造函数将创建新的唯一ptrs并复制内容。 为了完整起见,也请移动构造函数。 这似乎可行( ideone link ),但这意味着我从我的意图中得到了帮助,这是这样的:

struct v_with_holder {
    // bunch of fields
    holder h;
}

// define struct_v, holder

对于这个可怕的事情:

class holder;
struct v_with_holder {
    // a bunch of fields
    std::unique_ptr<holder> ph;
    holder& h;

    friend void swap(v_with_holder& first, v_with_holder& second) 
    {
        using std::swap;
        // swap a bunch of fields
        swap(first.ph, second.ph);
    }

    v_with_holder(); 
    ~v_with_holder();
    v_with_holder(const v_with_holder& other);
    v_with_holder(v_with_holder&& other);
    v_with_holder& operator=(v_with_holder other);
};

// define struct_v, holder

v_with_holder::v_with_holder() : ph(new holder), h(*ph) { }
v_with_holder::~v_with_holder() { }
v_with_holder::v_with_holder(const v_with_holder& other) : ph(new holder), h(*ph)
{
    // copy a bunch of fields
    h = other.h;
}
v_with_holder::v_with_holder(v_with_holder&& other) : v_with_holder()
{
    swap(*this, other);
}
v_with_holder& v_with_holder::operator=(v_with_holder other)
{
    swap(*this, other);
    return *this;
}

一切都是为了避免循环依赖!

当然,必须有更好的方法。 告诉我有更好的方法。 请。 这是什么更好的方法?

为什么不简单地做:

struct v_with_holder {
    // bunch of fields
    holder *h; //Pointer to holder is of known size
};

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

好的,看来我可以转发声明v_with_holder

struct v_with_holder;

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

struct v_with_holder
{
    holder h;
};

我没有意识到typedef可以与前向声明的类型一起使用,或者std::vector可以采用未声明的类型。 根据这个问题和答案 ,我认为它不可能,但是到目前为止,它已经在ideone,G ++ 4.8.1和MSVC 2012上奏效。

问题仍然存在,如果这不可能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM