C++11 class 与字符串联合 shared_ptr
C++11 class with union of string and shared_ptr
(这有点类似于 this question, and inspired by the 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 库)。
我看不出有任何理由不像您对 std::string
那样对 std::shared_ptr
使用展示位置 new
。只需分配一个值,如
clos = v.clos;
是不安全的,因为它会使用可能指向垃圾内存的 this
指针调用 std::shared_ptr
的复制赋值运算符。它可能会尝试 delete
不存在的东西。
同样,在您的复制赋值运算符中,您应该在放置新对象之前销毁旧对象,否则旧值将泄漏。
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.
如果您使用 copy & swap idiom,代码可能会变得更易于维护。因为我没有看到不使用它有任何明显的性能提升,所以我认为它不会在这里花费你任何额外的费用。
(这有点类似于 this question, and inspired by the 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 库)。
我看不出有任何理由不像您对 std::string
那样对 std::shared_ptr
使用展示位置 new
。只需分配一个值,如
clos = v.clos;
是不安全的,因为它会使用可能指向垃圾内存的 this
指针调用 std::shared_ptr
的复制赋值运算符。它可能会尝试 delete
不存在的东西。
同样,在您的复制赋值运算符中,您应该在放置新对象之前销毁旧对象,否则旧值将泄漏。
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.
如果您使用 copy & swap idiom,代码可能会变得更易于维护。因为我没有看到不使用它有任何明显的性能提升,所以我认为它不会在这里花费你任何额外的费用。