C ++ Union用法

时间:2016-01-03 16:09:21

标签: c++ unions

到目前为止,我刚刚使用工会来存储会员A或会员B. 我现在发现自己想要在运行时更改已使用的成员

union NextGen {
    std::shared_ptr<TreeRecord> Child = nullptr;
    std::vector<std::shared_ptr<TreeRecord>> Children;
};

我目前的用法:

void TreeRecord::AddChild(const std::shared_ptr<TreeRecord>& NewChild) {
    if(_childCount == 0) {
        _nextGeneration.Child = NewChild;
        _childCount++;
    } else if(_childCount == 1) {
        //This is not clear to me:
        //Do I have to set Child to nullptr first?
        //Do I need to clear the Children vecor?
        //Or will it work like this?
        _nextGeneration.Children.push_back(_nextGeneration.Child);
        _nextGeneration.Children.push_back(NewChild);
        _childCount++;
    } else {
        _nextGeneration.Children.push_back(NewChild);
        _childCount++;
    }
}

新实施(尝试):

typedef std::shared_ptr<TreeRecord> singlechild_type;
typedef std::vector<std::shared_ptr<TreeRecord>> children_type;



union {
    singlechild_type _child;
    children_type _children;
};



void TreeRecord::AddChild(const singlechild_type& NewChild) {
    if(_childCount == 0) {
        _child = NewChild;
        _childCount = 1;

    } else if(_childCount == 1) {
        singlechild_type currentChild = _child; //Copy pointer
        _child.~singlechild_type(); //Destruct old union member
        new (&_children) children_type(); //Construct new union member
        _children.push_back(currentChild); //Add old child to vector
        _children.push_back(NewChild); //Add new child to vector
        _childCount = 2;

    } else {
        _children.push_back(NewChild);
        _childCount++;
    }
}

2 个答案:

答案 0 :(得分:2)

您需要符合C++11标准的编译器。阅读union - s。

通常,您需要显式调用旧联合成员的析构函数,然后调用新联合成员的构造函数。实际上,您最好拥有tagged unions,实际的union是匿名的,并且是某个类的成员:

class TreeRecord;

class TreeRecord {
   bool hassinglechild;
   typedef std::shared_ptr<TreeRecord> singlechild_type;
   typedef std::vector<std::shared_ptr<TreeRecord>> children_type;
   union {
     singlechild_type child;  // when hassinglechild is true
     children_type children;  // when hassinglechild is false
   }
   TreeRecord() : hassinglechild(true), child(nullptr) {};
   void set_child(TreeRecord&ch) {
     if (!hassinglechild) {
       children.~children_type();
       hassinglechild = true;
       new (&child) singlechild_type(nullptr);
     };
     child = ch;
   }
   /// other constructors and destructors skipped
}

请注意,我明确调用了析构函数~children_type(),然后我使用展示位置new显式调用child的构造函数。

不要忘记关注rule of five

另见boost::variant

顺便说一句,您的代码建议您在拥有child的情况下和具有children的单元素向量的情况进行区分。这是自愿而有意义的吗?

PS。在某些语言中,特别是Ocaml,标记的联合(a.k.a.和类型)比在C ++ 11中更容易定义和实现....参见algebraic data types的wikipage。

答案 1 :(得分:1)

注意,使用i的多个元素会同时调用未定义的行为,例如

union

正如@BasileStarynkevitch所提到的,一种方法是避免这是一个标记的联合。