从美学的角度来看,它必须是第一个变体。您必须对语言标准和编译器作者有一定的信心,才能不需要像临时这样的愚蠢工件来促进此处的优化。
让我们检查一下是否确实如此。首先,请允许我稍微抽象一下您的示例并map
用一个类替换foo
,而不定义它的各种方法;并假设没有任何异常:
#include <utility>
// Originally this was an std::map, replaced with
// an "opaque" class to shorten the output and
// prevent inlining and conflation of
// std-map-related code with the rest of the code
struct foo {
foo() noexcept;
foo(const foo&) noexcept;
foo(foo&&) noexcept;
foo& operator=(foo&&) noexcept;
foo& operator=(const foo&) noexcept;
~foo() noexcept;
};
struct dest_t { foo data; };
foo get_foo() noexcept;
void do_stuff_with(const dest_t& dest) noexcept;
void move_from_intermediate() noexcept {
dest_t dest;
auto temp = get_foo();
dest.data = std::move(temp);
do_stuff_with(dest);
}
void straight_assignment() noexcept {
dest_t dest;
dest.data = get_foo();
do_stuff_with(dest);
}
现在,如果我们在 GodBolt 上编译它,我们会看到 GCC(主干)为这两个函数生成相同的汇编代码。那包含着:
- 1 建设
- 2 次破坏
- 1 移动任务
- 1 呼叫
get_foo()
- 1 呼叫
do_stuff_with()
在这两种情况下。clang (trunk) 也将产生相同的代码,直到轻微的重新排序——但与 GCC 的代码不完全相同。