C :包含其属于类的联合

C++: union that contains class it belongs to

本文关键字:属于 包含其      更新时间:2023-10-16

虽然编译了此代码而没有任何错误,但我怀疑它是否会按预期工作。这样的筑巢吗?我不能使用Boost和C 17。

class Node;
typedef struct Value {      
    ValueTag type;
    union {         
        std::int32_t                          integerValue;
        std::float_t                          floatValue;
        bool                                  boolValue;
        std::vector<Node>                     arrayValue;
        std::unordered_map<std::string, Node> dictionaryValue;
    };          
} Value;
class Node {                
private:        
    Value m_value;          
public:                 
    virtual ~Node();    
};

我怀疑它会按预期工作。

你是正确的。不会。首先,如果您尝试构建Node,它实际上不会编译。您会得到类似的东西:

prog.cc:26:10: error: call to implicitly-deleted default constructor of 'Node'
    Node n;
         ^

那是因为在union中,任何非平凡操作都被隐式删除。您必须定义~Value()才能做正确的事情。假设type是我们实际上是联合中哪个元素的索引,则可以打开它并调用适当的破坏者。然后做同样的事情以复制和移动。

也就是说,不完整的类型的嵌套也不正常。只要在首次使用前完成,vector就可以具有不完整的类型。但是unordered_map没有此津贴。您将必须将值类型包装在其他内容中 - 例如unique_ptr<Node>shared_ptr<Node>

您在Value中拥有的是一种具有一百万个不同名称的常见模式:歧视的联合,总和,或者最常见的是variant。我建议您改用std::variant(如果您使用的是最近的编译器来支持此类内容)或boost::variant(否则)(否则)。因此,您有:

using Value = variant<int32_t, float, bool,
    std::vector<Node>, std::unordered_map<std::string, Node>>;

这种类型已经可破坏,可复制,可动且可供您访问。

edit 我最初的答案是不正确/误导的,请忽略它。由于原因,请参见下面的评论。CANSES STD ::变体或Boost ::变种反正:)

非平原data(pod)在c- unions中不安全。

尤其是对于此Proplem std ::变体的C 17标准。您可以将Boost ::变体用于C 的早期版本。

问题是,联盟对建筑构造和破坏者一无所知。因此,不可能用联合元素做更多的一般性事情,这是必要的(例如动态内存分配)