首页 > 解决方案 > 如何在不调用析构函数的情况下将值移出 std:optional ?

问题描述

我正在尝试编写一个函数,make_foo它将“解包” a std::optional< foo >,返回包含的值。该函数假定可选选项已启用,因此不对optional.

下面是我的实现,以及编译的程序集以供参考。我有几个关于编译器输出的问题:

  1. 为什么这会导致代码分支?optional::operator*提供对包含值的未经检查的访问,所以我不希望看到任何分支。

  2. 为什么foo会调用析构函数?注意on_destroy()程序集中的调用。我们如何在不调用析构函数的情况下将包含的值移出可选值?

螺栓链接

C++17 源代码

#include <optional>

extern void on_destroy();

class foo {
  public:
    ~foo() { on_destroy(); }
};

extern std::optional< foo > foo_factory();

// Pre-condition: Call to foo_factory() will not return nullopt
foo make_foo() {
    return *foo_factory();
}

优化的编译器输出 (Clang 11)

make_foo():                           # @make_foo()
        push    rbx
        sub     rsp, 16
        mov     rbx, rdi
        lea     rdi, [rsp + 8]
        call    foo_factory()
        cmp     byte ptr [rsp + 9], 0
        je      .LBB0_2
        mov     byte ptr [rsp + 9], 0
        call    on_destroy()
.LBB0_2:
        mov     rax, rbx
        add     rsp, 16
        pop     rbx
        ret

标签: c++c++17destructormove-semanticsstdoptional

解决方案


你的方法或多或少是这样的:

foo make_foo() {
   auto x = foo_factory(); 
   return *x;
}

从工厂返回的产品在哪里xoptional代码中未命名的临时文件)。当x被销毁时,它要么调用所包含对象的析构函数(当有一个时)。或者它不会破坏包含的对象(当没有对象时)。简而言之:foo您从中移出的仍然需要被销毁,即使您知道可选项确实包含它,编译器也不能,因此分支。

如何在不调用析构函数的情况下将值移出 std:optional ?

你不能。即使是从对象移动的最终也需要被销毁。


推荐阅读