Pergunta

Por favor, considere as três funções.

std::string get_a_string()
{
    return "hello";
}

std::string get_a_string1()
{
    return std::string("hello");
}

std::string get_a_string2()
{
    std::string str("hello");
    return str;
}
  1. O RVO será aplicado em todos os três casos?
  2. Tudo bem retornar um temporário como no código acima? Eu acredito que está tudo bem, pois estou devolvendo por valor em vez de retornar qualquer referência a ele.

Alguma ideia?

Foi útil?

Solução

Em dois primeiros casos, a otimização do RVO ocorrerá. O RVO é um recurso antigo e a maioria dos compiladores suporta. O último caso é chamado NRVO (chamado RVO). Esse é um recurso relativamente novo do C ++. O padrão permite, mas não requer implementação do NRVO (assim como RVO), mas alguns compiladores o suportam.

Você poderia ler mais sobre RVO no item 20 do livro de Scott Meyers C ++ mais eficaz. 35 novas maneiras de melhorar seus programas e projetos.

Aqui é um bom artigo sobre o NRVO no Visual C ++ 2005.

Outras dicas

Primeiro, não há problema em devolver um valor temporário por valor que é o que você faz. É copiado e, embora o original sai do escopo, a cópia não o fará e pode ser usada com segurança pelo chamador.

Segundo, todos os três casos são de fato idênticos (já que você não acessa o temporário no terceiro caso de qualquer maneira) e um compilador pode até emitir o mesmo código para todos eles. Portanto, pode usar o RVO nos três casos. Isso é totalmente dependente do compilador.

Todos os casos estão corretos. Todos eles construirão um temporário e aplicarão o construtor de cópias do tipo de retorno. Necessariamente, se não houver construtor de cópia, o código falhará.

O RVO acontecerá nos três casos sob a maioria dos compiladores. A única diferença é a última em que o padrão não o força. Isso porque você tem uma variável nomeada. Mas a maioria dos compiladores é inteligente o suficiente para aplicar o RVO a ele ainda ... quanto mais posterior a variável nomeada é declarada e, quanto menos transformações for aplicada, as melhores chances de o RVO serem aplicadas a uma variável nomeada.

Aliás, o retorno de uma referência é obviamente possível, como você pode ter visto em outro código. O que você não deve fazer é retornar um objeto local de referência.

std::string& get_a_string2()
{
    std::string str("hello");
    return str; //error!
}

Produzirá um erro de tempo de compilação, como você sabe. No entanto,

std::string& get_a_string2(std::string& str)
{
    // do something to str
    return str; //OK
}

Vai funcionar bem. Nesse caso, não há construção ou construção de cópias envolvidas. Simplesmente a função retorna uma referência ao seu argumento.

  1. Depende do seu compilador - a que plataforma você está se referindo? A melhor maneira de descobrir é compilar um muito pequeno aplicativo de teste e verifique o ASM que seu compilador produz.

  2. Sim, tudo bem, embora você nunca mencione o que está preocupado; Rapidez? estilo? Você pode um local temporário para uma referência const - a vida útil do temporário será estendida à vida útil da referência - tente e veja por si mesmo! (Herb Sutter exaplina isso aqui) Veja o final da postagem, por exemplo.

IMO você é quase sempre melhor confiar no seu compilador para otimizar seu código para você. Existem muito poucos casos em que você precisa se preocupar com esse tipo de coisa (o código de nível muito baixo é uma dessas áreas, onde você é interativo com registros de hardware).

int foo() { return 42; }

int main(int, char**)
{
    const int &iRef = foo();
    // iRef is valid at this point too!
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top