C++联合使用 [英] C++ Union usage

查看:40
本文介绍了C++联合使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

到目前为止,我只是使用联合来存储成员 A 或成员 B.
我现在发现自己想要在运行时更改使用的成员.

So far I have just used unions to store either member A or member B.
I do now find myself in the case where I want to change the used member during runtime.

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++;
    }
}

推荐答案

您需要一个 C++11 兼容编译器.阅读union-s.

You need a C++11 compliant compiler. Read about union-s.

一般来说,你需要显式调用旧联合成员的析构函数,然后调用新联合成员的构造函数.实际上,您最好使用标记联合,并使用实际的联合 匿名并且是某个班级的成员:

In general, you need to explicitly call the destructor of the old union member, and then the constructor of the new union member. Actually, you'll better have tagged unions, with the actual union being anonymous and member of some class:

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
   /// more code needed, per rule of five
}

请注意,我显式调用析构函数 ~children_type() 然后我使用位置 new显式调用构造函数代码>子.

Notice that I am explicitly calling the destructor ~children_type() then I am using the placement new to explicitly call the constructor for child.

不要忘记遵循五法则.所以你上面需要更多的代码

Don't forget to follow the rule of five. So you need more code above

另见 boost::variant

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

BTW your code is suggesting that you distinguish the case when you have a child and the case when you have a one-element vector of children. Is that voluntary and meaningful?

附注.在某些语言中,特别是 Ocaml,标记联合(又名和类型)比在 C++11 中更容易定义和实现......请参阅 代数数据类型.

PS. In some languages, notably Ocaml, tagged unions (a.k.a. sum types) are considerably easier to define and implement than in C++11.... See wikipage of algebraic data types.

这篇关于C++联合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆