C++ C++;11具有字符串和共享\u ptr并集的类
(这有点类似于,并受……的启发,但并不完全如此……) 在惯用C++11编写类似于模式的解释器的上下文中,让我们假设我需要字符串、int和一些闭包的标记并集。所以我可能会编写代码:C++ C++;11具有字符串和共享\u ptr并集的类,c++,c++11,discriminated-union,C++,C++11,Discriminated Union,(这有点类似于,并受……的启发,但并不完全如此……) 在惯用C++11编写类似于模式的解释器的上下文中,让我们假设我需要字符串、int和一些闭包的标记并集。所以我可能会编写代码: #include <string> #include <new> #include <memory> #include <functional> enum kind { nothing, string, integer, closure }; class Value {
#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...
};
但也许我应该在共享\u ptr
上使用放置新
我不想为此使用Boost(或任何非标准C++11库)。我看不出有任何理由不为
std::shared\u ptr
使用placementnew
,就像对std::string
那样。简单地赋值,如中所示
clos = v.clos;
不安全,因为它将调用std::shared_ptr
的copy assignment操作符,并使用可能指向垃圾内存的this
指针。它可能试图删除不存在的内容
同样,在“复制指定”操作符中,应在放置新对象之前销毁旧对象,否则旧值将泄漏
using std::string;
using std::shared_ptr;
if (&v == this)
return *this; // self-assignment
switch (this->k)
{
case string:
this->str.~string();
break;
case closure:
this->clos.~shared_ptr();
break;
}
this->k = nothing;
// Now we are ready to take the new value.
如果使用,代码可能会更易于维护。因为我看不到不使用它会带来任何明显的性能提升,所以我不认为这会让您付出额外的代价。为什么您会犹豫对
共享的
使用placementnew
,而对字符串使用placement?我认为将共享的ptr
分配给未初始化的内存并不安全。它可能会破坏某些垃圾位的“托管对象”。哦,在copy assignment操作符中,您应该在重新构建之前销毁字符串,否则它将泄漏旧的缓冲区。这可能应该成为一个答案,不是注释……如果您不想直接使用Boost,您至少应该从中学习如何在Boost::variant
中以类型安全的方式进行操作,并使用类似的方法,如访问者模式而不是开关等。至少您会检测到访问者是否在编译时而不是在运行时处理所有变体。@Slava问题是关于C++11的union
s,我不认为boost:variant
是一个很好的灵感来源,因为它的很大一部分目的是为了绕过在C++11放松之前为union
s设置的限制。
using std::string;
using std::shared_ptr;
if (&v == this)
return *this; // self-assignment
switch (this->k)
{
case string:
this->str.~string();
break;
case closure:
this->clos.~shared_ptr();
break;
}
this->k = nothing;
// Now we are ready to take the new value.