C ++ 11 класс с объединением строки и shared_ptr

(это немного похоже на этот вопрос, и вдохновлен 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) для этой цели.

2

Решение

Я не вижу причин не использовать размещение 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.

Код, вероятно, станет легче поддерживать, если вы используете копия & своп идиома. Поскольку я не вижу очевидного прироста производительности от его использования, я не думаю, что это будет стоить вам здесь чего-то дополнительного.

3

Другие решения


По вопросам рекламы [email protected]