Я всегда считал, что при захвате какого-либо тяжелого объекта, возвращаемого функцией по значению, правильнее всего делать это с помощью константной ссылки, чтобы избежать дополнительного копирования из временной переменной в целевую. Этот способ продлевает срок службы временных изделий, как описано в статье Херба Саттера. Теперь я поигрался с Godbolt, чтобы сравнить код, сгенерированный обоими способами, и, к моему удивлению, код, который фиксирует возвращаемое временное значение по значению, выглядит короче. Я знаю об оптимизации RVO и NRVO, но я тестировал код на уровне оптимизации -O0. Выполняются ли эти оптимизации даже для -O0 и существует ли еще случай, когда предпочтительнее захват возвращаемого значения по константной ссылке?
Вот код C++:
Код: Выделить всё
#include
using namespace std;
string foo() {
return "test";
}
void bar() {
auto y = foo();
}
void dar() {
const auto& z = foo();
}
Вот сгенерированная GCC 14.2, сборка x86-64 для функций bar и dar:
Код: Выделить всё
bar():
push rbp
mov rbp, rsp
sub rsp, 32
lea rax, [rbp-32]
mov rdi, rax
call foo[abi:cxx11]()
lea rax, [rbp-32]
mov rdi, rax
call std::__cxx11::basic_string::~basic_string() [complete object destructor]
leave
ret
dar():
push rbp
mov rbp, rsp
sub rsp, 48
lea rax, [rbp-48]
mov rdi, rax
call foo[abi:cxx11]()
lea rax, [rbp-48]
mov QWORD PTR [rbp-8], rax
lea rax, [rbp-48]
mov rdi, rax
call std::__cxx11::basic_string::~basic_string() [complete object destructor]
leave
ret
Сгенерированная сборка для функции dar, которая фиксирует возвращаемое значение по константной ссылке, на две инструкции длиннее:
Код: Выделить всё
lea rax, [rbp-48]
mov QWORD PTR [rbp-8], rax
Вот ссылка на код в Godbolt.
Подробнее здесь:
https://stackoverflow.com/questions/790 ... it-by-cons