С эстетической точки зрения, имеет в качестве первого варианта. Вы должны иметь некоторую веру в языковой стандарт и авторов компилятора, чтобы не требовать глупого артефакта, такого как временный, для облегчения оптимизации здесь.
Давайте проверим, так ли это на самом деле. Во-первых, позвольте мне немного абстрагировать ваш пример и заменить 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 (trunk) создает одинаковый код сборки для обеих функций. Это включает в себя:
- 1 конструкция
- 2 разрушения
- 1 задание на перемещение
- 1 звонок на
get_foo()
- 1 звонок на
do_stuff_with()
в обоих случаях. clang (trunk) также выдаст тот же код, вплоть до небольшого переупорядочения, но не совсем того же кода, что и GCC.