Избегать временного при использовании boost :: необязательный

boost :: дополнительная поддержка in_place конструкция, например, так:

#include <boost/optional.hpp>
#include <boost/utility/typed_in_place_factory.hpp>

class Foo
{
int a,b;

public:
Foo(int one, int two) : a(one),b(two) {}
};int main()
{
boost::optional<Foo> fooOpt(boost::in_place<Foo>(1,3));
}

Как только у нас будет инициализированный fooOpt, есть ли способ присвоения ему нового Foo без создания временного?

Что-то вроде :

fooOpt = boost::in_place<Foo>(1,3);

Спасибо!

8

Решение

повышение :: опционально

#include <boost/optional.hpp>

int main() {
boost::optional<int> x;
x = boost::in_place(3);
}

Мы также можем показать (через код), что это строит объект на месте, сделав Foo наследовать от boost::noncopyable:

#include <boost/optional.hpp>
#include <boost/noncopyable.hpp>

class Foo : boost::noncopyable {
public:
Foo(int one, int two) {}
};int main() {
boost::optional<Foo> x;
x = boost::in_place(3, 4);
}

std :: необязательный (в конце концов …)

Со временем мы получим доступ к std::optional, Этот тип будет реализовывать emplace() метод, который будет осуществлять строительство на месте, а также.

#include <optional>

int main() {
std::optional<int> x;
x.emplace(3);
}

boost :: опционально (скоро …)

В версии 1.56.0, boost::optional также будет реализовывать emplace() метод, о котором я говорил для std :: необязательный. Итак, давайте посмотрим, что:

#include <boost/optional.hpp>

int main() {
boost::optional<int> x;
x.emplace(3);
}
9

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

Документированный интерфейс не поддерживает это.

Однако, если вы знаете, что никто не расширяет boost::optionalЯ считаю, что это может быть технически обоснованным:

template<typename T, typename... Us>
void emplace_replace( boost::optional<T>& target, Us&&... us ) {
target.~boost::optional<T>();
try {
new (&target) boost::optional<T>( boost::in_place( std::forward<Us>(us)...) );
} catch(...) {
new (&target) boost::optional<T>();
throw;
}
}

Здесь мы уничтожаем target, а затем реконструировать новый boost::optional<T> на своем месте с постройкой на месте. trycatch конструкция должна сделать большинство throws во время строительства безопасно: если он выбрасывает, вы получите пустой optional,

Это естественно ведет себя иначе, чем operator= Ожидается.


В 1.55 (а может и раньше?) Есть недокументированный operator= это занимает Expr который поддерживает boost::in_place а также boost::in_place<T>, Смотрите ответ @ sharth для подробного использования.

Мое быстрое чтение показывает, что набранный На месте фабрики с помощью этого метода может быть недостаточно защиты:

boost::optional<int> test;
// test = boost::in_place<double>( 3 ); // <-- very dangerous
test = boost::in_place( 3 ); // safe
test = boost::in_place( 3.0 ); // safe

Если тип передается непосредственно in_place<?>, он может генерировать typed_in_place_factory, которые опасны (они передают тип и не проверяют его совместимость). Так что не передавайте никакие типы boost::in_place,

Это (из чтения исходного кода) делает что-то похожее на мой код уничтожения / реконструкции, за исключением того, что оно делает это без разрушения всего optional и просто уничтожает сохраненные данные и делает их неинициализированными.


В бусте 1.56b1, устанавливать был добавлен в boost::optional, Это делает что-то похожее на обе вышеуказанные операции. (через @AkiraTakahashi)


std::optional предложения, которые я видел, включали функцию члена .emplace( Us&&... ) который поддерживает замену emplace напрямую.

3

Как только вы узнаете, что он есть, вы можете создать обычную ссылку:

optional<Foo> optFoo = ....;
Foo &foo = *optFoo;
foo.x = 3;
foofun(foo);
foo = Foo();
0
По вопросам рекламы [email protected]