使用boost::optional时避免使用temporary

Avoiding temporary when using boost::optional

本文关键字:temporary boost optional 使用      更新时间:2023-10-16

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);

谢谢!

boost::optional

#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也将实现我在std::optional中提到的emplace()方法。我们看一下:

#include <boost/optional.hpp>
int main() {
    boost::optional<int> x;
    x.emplace(3);
}

文档中的接口不支持此操作

然而,如果你知道没有人扩展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>try - catch构造应该使构造期间的大多数throw s是安全的:如果它抛出,你最终得到一个空的optional

这自然与operator=的预期行为不同。


在1.55(可能更早?)中,有一个未记录的operator=,它接受一个支持boost::in_placeboost::in_place<T>Expr

我的快速阅读表明,通过此方法键入的就地工厂可能没有足够的保护:

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

这(从阅读源代码)做了一些类似于我的destroy/rebuild代码,除了它没有破坏整个optional,只是破坏存储的数据,使其未初始化。


在boost 1.56b1中,放置被添加到boost::optional。它所做的事情类似于上述两个操作。(通过@AkiraTakahashi)


我看到的std::optional提案包含了一个成员函数.emplace( Us&&... ),它支持直接替换位置

一旦你知道它在那里,你就可以创建一个普通的引用:

optional<Foo> optFoo = ....;
Foo &foo = *optFoo;
foo.x = 3;
foofun(foo);
foo = Foo();