问题
(this is a bit similar to this question, and inspired by the C++11 FAQ on union but not exactly so...)
In the context of coding a Scheme-like interpreter in idiomatic C++11 Let's suppose I want a tagged union of a string, an int, and some closure. So I would probably code:
#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...
};
Now what about the closure
case? For the copy constructor and the assignment operator, I am tempted to code:
case closure: clos = v.clos; break;
But perhaps should I use a placement new
on a shared_ptr
?
I don't want to use Boost (or any non standard C++11 library) for that purpose.
回答1:
I don't see any reason not to use placement new
for the std::shared_ptr
just as you did for the std::string
. Simply assigning a value as in
clos = v.clos;
is not safe as it will call the copy-assignment operator of std::shared_ptr
with a this
pointer that potentially points to garbage memory. It might try to delete
something that isn't there.
Likewise, in your copy-assignment operator, you should destroy the old object before you emplace the new one or the old value will leak.
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.
The code will probably become easier to maintain if you use the copy & swap idiom. Since I don't see any obvious performance gains of not using it, I don't think it will cost you anything extra here.
来源:https://stackoverflow.com/questions/28613109/c11-class-with-union-of-string-and-shared-ptr