(это немного похоже на этот вопрос, и вдохновлен C ++ 11 FAQ по объединению но не совсем так …)
В контексте кодирования Scheme-подобного интерпретатора в идиоматическом 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...
};
Теперь насчет closure
дело? Для конструктора копирования и оператора присваивания мне хочется написать код:
case closure: clos = v.clos; break;
Но, возможно, я должен использовать место размещения new
на shared_ptr
?
Я не хочу использовать Boost (или любую нестандартную библиотеку C ++ 11) для этой цели.
Я не вижу причин не использовать размещение new
для std::shared_ptr
так же, как вы сделали для std::string
, Просто присваивая значение как в
clos = v.clos;
не является безопасным, так как вызовет оператор копирования-назначения std::shared_ptr
с this
указатель, который потенциально указывает на мусорную память. Это может попытаться 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.
Код, вероятно, станет легче поддерживать, если вы используете копия & своп идиома. Поскольку я не вижу очевидного прироста производительности от его использования, я не думаю, что это будет стоить вам здесь чего-то дополнительного.