【发布时间】:2015-02-20 02:01:23
【问题描述】:
(这有点类似于this question,并受到C++11 FAQ on union 的启发,但并非完全如此......)
在用惯用的 C++11 编写类似 Scheme 的解释器的上下文中假设我想要一个字符串、一个 int 和一些闭包的标记联合。所以我可能会编码:
#include <string>
#include <new>
#include <memory>
#include <functional>
enum kind { nothing, string, integer, closure };
class Value {
enum kind k;
typedef std::string string_t;
union {
std::string str;
int num;
std::shared_ptr<std::function<Value(std::vector<Value>)>> clos;
};
public:
Value (const Value &v)
: k(none) {
switch (v.k) {
case none: break;
case string: new(&str)string_t(v.str); break;
case integer: num = v.num; break;
/// what about closure-s?
}
k = v.k;
};
Value& operator = (const Value&v) {
switch (v.k) {
case none: break;
case string: new(&str)string_t(v.str); break;
case integer: num = v.num; break;
/// what about closure-s?
}
k = v.k;
}
/// etc...
};
现在closure 案例呢?对于复制构造函数和赋值运算符,我很想写代码:
case closure: clos = v.clos; break;
但也许我应该在shared_ptr 上使用一个展示位置new?
我不想为此目的使用 Boost(或任何非标准 C++11 库)。
【问题讨论】:
-
您为什么犹豫将
new用于shared_ptr和string?我不认为将shared_ptr分配给未初始化的内存是安全的。它可能会尝试破坏一些垃圾位的“托管对象”。哦,在复制赋值运算符中,你应该在重建之前销毁string,否则它会泄漏旧缓冲区。 -
这可能应该成为一个答案,而不是评论......
-
如果你不想直接使用 Boost,你至少应该从那里学习如何在
boost::variant中输入安全的方式并使用类似的方法,即访问者模式而不是 switch 等。至少你将检测访问者是否在编译时而不是运行时处理所有变体。 -
@Slava 鉴于问题是关于 C++11 的
unions,我不认为boost:variant是一个很好的灵感来源,因为它的很大一部分目的是为了工作围绕在 C++11 放宽之前对unions 的限制。
标签: c++ c++11 discriminated-union