C++ C++;11具有字符串和共享\u ptr并集的类

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 {

(这有点类似于,并受……的启发,但并不完全如此……)

在惯用C++11编写类似于模式的解释器的上下文中,让我们假设我需要字符串、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...
};
但也许我应该在
共享\u ptr
上使用放置


我不想为此使用Boost(或任何非标准C++11库)。

我看不出有任何理由不为
std::shared\u ptr
使用placement
new
,就像对
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.

如果使用,代码可能会更易于维护。因为我看不到不使用它会带来任何明显的性能提升,所以我不认为这会让您付出额外的代价。

为什么您会犹豫对
共享的
使用placement
new
,而对
字符串
使用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.