C++ 联合用法
C++ Union usage
到目前为止,我只是使用联合来存储成员 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++;
}
}
您需要 C++11 compliant compiler. Read about union-s。
一般情况下,需要显式调用旧联合成员的析构函数,然后再调用新联合成员的构造函数。实际上,你最好有 tagged unions,实际的 union
是匿名的,并且是某些 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
来 显式 调用 child
的构造函数.
别忘了关注rule of five。所以你需要更多上面的代码
顺便说一下,您的代码建议您区分 child
的情况和 children
的 one-element 向量的情况。那是自愿的和有意义的吗?
PS。在某些语言中,特别是 Ocaml,标记联合(a.k.a.sum 类型)比在 C++11 中更容易定义和实现....参见 algebraic data types.
的维基页面
请注意,使用 union
的多个元素会同时调用未定义的行为,例如
_nextGeneration.Children.push_back(_nextGeneration.Child);
正如@BasileStarynkevitch 提到的,一种方法是避免这是一个标记联合。
到目前为止,我只是使用联合来存储成员 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++;
}
}
您需要 C++11 compliant compiler. Read about union-s。
一般情况下,需要显式调用旧联合成员的析构函数,然后再调用新联合成员的构造函数。实际上,你最好有 tagged unions,实际的 union
是匿名的,并且是某些 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
来 显式 调用 child
的构造函数.
别忘了关注rule of five。所以你需要更多上面的代码
顺便说一下,您的代码建议您区分 child
的情况和 children
的 one-element 向量的情况。那是自愿的和有意义的吗?
PS。在某些语言中,特别是 Ocaml,标记联合(a.k.a.sum 类型)比在 C++11 中更容易定义和实现....参见 algebraic data types.
的维基页面请注意,使用 union
的多个元素会同时调用未定义的行为,例如
_nextGeneration.Children.push_back(_nextGeneration.Child);
正如@BasileStarynkevitch 提到的,一种方法是避免这是一个标记联合。