我处于两个类的定义之间存在循环依赖关系循环的情况下,(据我所知)两个类都需要另一个类型为完整类型才能正确定义它们。

用简化的术语来说,我需要的是正在发生的事情的简化版本:

struct Map;

struct Node {
    // some interface...
private:
    // this cannot be done because Map is an incomplete type
    char buffer[sizeof(Map)];
    // plus other stuff...
    void* dummy;
};

struct Map {
    // some interface...
private:
    // this is Map's only member
    std::unordered_map<std::string, Node> map_;
};

这种情况实际上比上述情况更为复杂,因为Node实际上将是一种变体类型(类似于boost::variant),它使用new放置来显式​​构造预分配的多种对象之一(并具有正确的对齐方式,我将我忽略了这种简化)缓冲区:因此,该缓冲区并非完全是sizeof(Map),而是一些依赖于sizeof(Map)的计算常数。

显然,问题在于仅向前声明sizeof(Map)Map不可用。此外,如果我更改声明的顺序以先转发声明Node,则Map的编译将失败,因为当std::unordered_map<std::string, Node>是不完整的类型时,至少在我的GCC 4.8.2上,无法实例化Node。 (我知道它对libstdc++版本的依赖比对GCC版本的依赖更大,但我不容易知道如何找到它……)

作为替代方案,我正在考虑以下解决方法:
struct Node {
    // some interface...
private:
    // doing this instead of depending on sizeof(Map)
    char buffer[sizeof(std::unordered_map<std::string, void*>)];
    // other stuff...
    void* dummy;
};

struct Map {
    // some interface...
private:
    // this is Map's only member
    std::unordered_map<std::string, Node> map_;
};

// and asserting this after the fact to make sure buffer is large enough
static_assert (sizeof(Map) <= sizeof(std::unordered_map<std::string, void*>),
    "Map is unexpectedly too large");

这基本上是基于std::unordered_map<std::string, T>对于所有T都是相同的大小的假设,这在我使用GCC进行的测试中似乎成立。

因此,我的问题是三方面的:
  • C++标准中是否有任何要求该假设成立的内容? (我假设没有,但如果有,我会感到惊喜...)
  • 如果不是,则可以安全地假设它对所有合理的实现都成立,并且我的修订版中的静态断言永远不会触发吗?
  • 最后,对于我没有想到的这个问题,有更好的解决方法吗?我确定有可能我可以做一些显而易见的事情,而我却从未想到过,但是不幸的是我什么也没想到...
  • 最佳答案

    只是继续假设。然后在构建正确的static_assert时是正确的。

    有一些更高级的解决方案,例如弄清楚boost递归数据结构是如何工作的,并在此处应用该技术(可能需要编写自己的 map ),或者仅使用支持不完整数据结构的boost::容器。

    关于c++ - 假定所有的T的sizeof(std::unordered_map <std::string,T>)都是相同的,实际上是安全的吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30205748/

    10-12 22:23