O retorno por referência de rvalue é mais eficiente?

133

por exemplo:

Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}
Neil G
fonte

Respostas:

246
Beta_ab&&
Beta::toAB() const {
    return move(Beta_ab(1, 1));
}

Isso retorna uma referência pendente, assim como no caso de referência lvalue. Após o retorno da função, o objeto temporário será destruído. Você deve retornar Beta_abpor valor, como o seguinte

Beta_ab
Beta::toAB() const {
    return Beta_ab(1, 1);
}

Agora, ele está movendo corretamente um Beta_abobjeto temporário para o valor de retorno da função. Se o compilador puder, ele evitará a movimentação por completo, usando o RVO (otimização do valor de retorno). Agora, você pode fazer o seguinte

Beta_ab ab = others.toAB();

E ele moverá a construção do temporário para ab, ou fará o RVO para omitir fazer uma movimentação ou copiar completamente. Eu recomendo que você leia as BoostCon09 Rvalue References 101, que explicam o assunto e como (N) RVO interage com isso.


Seu caso de retornar uma referência rvalue seria uma boa idéia em outras ocasiões. Imagine que você tem uma getAB()função que você invoca frequentemente temporariamente. Não é ideal fazê-lo retornar uma referência constante para temporários rvalores. Você pode implementá-lo assim

struct Beta {
  Beta_ab ab;
  Beta_ab const& getAB() const& { return ab; }
  Beta_ab && getAB() && { return move(ab); }
};

Observe que move, neste caso, não é opcional, porque abnão é um rvalue automático local nem temporário. Agora, o ref-qualifier && diz que a segunda função é chamada em temporários rvalue, fazendo o seguinte movimento, em vez de copiar

Beta_ab ab = Beta().getAB();
Johannes Schaub - litb
fonte
51
Eu sempre assumi que o problema de referência pendente desapareceu automaticamente quando o tipo de retorno era uma referência de valor-r. Ainda bem que resolvi isso antes de me morder. Os erros esmagadores da pilha são péssimos.
Deft_code 15/07/09
31
:) Realmente, as referências rvalue são "apenas referências", como as referências lvalue. eles não copiam ou armazenam nada.
Johannes Schaub - litb 10/03/10
9
o que o const & qualifier em um membro funciona mais do que um simples const?
Galinette (
4
+ 1-ed, mas link quebrado: BoostCon09 Rvalue Referências 101
Siu Ching Pong -Asuka Kenji- -
3
@ galinette Estes são ref-qualifiers .
Malcolm
2

Ele pode ser mais eficiente, por exemplo, em um contexto um pouco diferente:

template <typename T>
T&& min_(T&& a, T &&b) {
    return std::move(a < b? a: b);
}

int main() {
   const std::string s = min_(std::string("A"), std::string("B"));
   fprintf(stderr, "min: %s\n", s.c_str());
   return 0;
}

Como uma observação interessante, na minha máquina clang++ -O3gera 54 instruções para o código acima versus 62 instruções para o regular std::min. No entanto, -O0ele gera 518 instruções para o código acima e 481 para o regular std::min.

wonder.mice
fonte
Estou confuso com sua resposta. Tentou uma versão semelhante (talvez), mas falhou: ideone.com/4GyUbZ Você poderia explicar o porquê?
Deqing
Você usou a referência no objeto temporário for(:)e a integração no objeto desalocado. Correção: ideone.com/tQVOal
wonder.mice
3
Essa resposta não está realmente errada? para o parâmetro de modelo T, T&& não é uma referência de valor r, mas sim uma referência universal e, nesse caso, devemos sempre chamar std :: forward <T>, não std :: move! Sem mencionar que esta resposta contradiz diretamente a mais votada acima.
Xdavidliu 03/11/19
@xdavidliu, esta resposta é um exemplo artificial de como o retorno por rvalue pode ser mais eficiente. std::move()é usado apenas como um elenco explícito para ilustrar o ponto mais claramente. Não é um código que você copia e cola no seu projeto. Não contradiz a resposta mais votada, porque um objeto temporário é criado dentro da função. O objeto retornado aqui é um dos argumentos (objetos temporários são destruídos como a última etapa na avaliação da expressão completa que (lexicamente) contém o ponto em que foram criados).
wonder.mice
2
@ wonder.mice então substitua T por std :: string; não há necessidade de usar modelos aqui, e usar T&& como uma referência de valor-r é apenas um estilo horrível que confunde desnecessariamente as pessoas novas em modelos e valores-r.
xdavidliu 15/04