C++联合使用 [英] C++ Union usage
问题描述
到目前为止,我只是使用联合来存储成员 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++;
}
}
推荐答案
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
顺便说一句,您的代码建议您区分具有 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屋!