【问题标题】:Avoiding temporary when using boost::optional使用 boost::optional 时避免临时
【发布时间】:2014-08-07 14:54:12
【问题描述】:

boost::optional 支持 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);

谢谢!

【问题讨论】:

    标签: c++ boost optional


    【解决方案1】:

    升压::可选

    #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::optional(最终...)

    最终,我们将访问std::optional。此类型将实现 emplace() 方法,该方法也将实现就地构造。

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

    boost::optional(很快...)

    在 1.56.0 版本中,boost::optional 还将实现我谈到的 std::optional 的 emplace() 方法。所以,让我们看看:

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

    【讨论】:

    • 第一个在原地构造一个临时的boost::optional&lt;int&gt;,然后将其分配给x——文档中的I see no operator= overload for boost::in_place
    • @Yakk Synopsis 页面下有一个。也许这是一个文档错误。 template&lt;class InPlaceFactory&gt; optional&amp; operator=(InPlaceFactory const&amp; f);
    • @Yakk:如果它不可复制,我们如何将它分配给x
    • 嗯。 Source code#if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) &amp;&amp; !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION),然后是template&lt;class Expr&gt; optional&amp; operator= ( Expr const&amp; expr ),其中assign_expr,其中constructassign_expr_to_initialized,其中第二个destroys 然后constructs。
    • @Yakk:无论出于何种原因,boost::optional 默认情况下不包含 typed_in_place_factory 标头。因此,如果我们确实包含它,您的代码会生成一个error: call to 'in_place' is ambiguous。但无论哪种方式,您都认为typed_in_place_factory 非常危险是正确的。
    【解决方案2】:

    文档化的接口不支持这个。

    但是,如果您知道没有人扩展 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&lt;T&gt;try-catch 构造应该使大多数throws 在构造过程中安全:如果它抛出,你最终会得到一个空的optional

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


    在 1.55(可能更早?)中,有一个未记录的 operator= 采用支持 boost::in_placeboost::in_place&lt;T&gt;Expr。详细使用请参见@sharth 的回答。

    我的快速阅读表明通过这种方法的 typed 就地工厂可能没有足够的防护:

    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&lt;?&gt;,它会生成一个typed_in_place_factory,这是很危险的(他们制作传入的类型,并且不检查它是否兼容)。所以不要将任何类型传递给boost::in_place

    这(通过阅读源代码)执行类似于我的销毁/重建代码的操作,但它不会破坏整个 optional,只是破坏存储的数据并使其未初始化。


    在 boost 1.56b1 中,emplace 已添加到 boost::optional。它执行与上述两种操作类似的操作。 (来自@AkiraTakahashi)


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

    【讨论】:

    • 您可以将 boost::optional 通过模板参数类型 sfinae 它只接受 boost::optional。此外,您可以在调试版本中声明 typeid。
    • 嗯.. 如果在该代码期间触发异常会发生什么?
    • @sharth 固定,有条件。
    • 作为附加信息,在 Boost 1.56.0 中,boost::optional 将支持 emplaceboost.org/doc/libs/1_56_0_b1/libs/optional/doc/html/…
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-03
      • 2021-11-04
      • 1970-01-01
      相关资源
      最近更新 更多