Quantos dados são copiados, ao retornar um std :: vector em uma função e quão grande será a otimização para colocar o std :: vector no free-store (no heap) e retornar um ponteiro, isto é:
std::vector *f()
{
std::vector *result = new std::vector();
/*
Insert elements into result
*/
return result;
}
mais eficiente do que:
std::vector f()
{
std::vector result;
/*
Insert elements into result
*/
return result;
}
?
c++
return-value
stdvector
Morten
fonte
fonte
f
?Respostas:
Em C ++ 11, esta é a forma preferida:
Ou seja, retorno por valor.
Com o C ++ 11,
std::vector
tem semântica de movimento, o que significa que o vetor local declarado em sua função será movido no retorno e em alguns casos até mesmo o movimento pode ser omitido pelo compilador.fonte
return std::move(v);
desativará a elisão de movimento mesmo que fosse possível com apenasreturn v;
. Portanto, o último é o preferido.Você deve retornar por valor.
O padrão possui uma característica específica para melhorar a eficiência do retorno por valor. É chamado de "elisão de cópia" e, mais especificamente, neste caso, a "otimização do valor de retorno nomeado (NRVO)".
Os compiladores não precisam implementá-lo, mas, novamente, os compiladores não precisam implementar o inlining de funções (ou realizar qualquer otimização). Mas o desempenho das bibliotecas padrão pode ser muito pobre se os compiladores não otimizam, e todos os compiladores sérios implementam inlining e NRVO (e outras otimizações).
Quando o NRVO for aplicado, não haverá cópia no seguinte código:
Mas o usuário pode querer fazer isso:
A elisão de cópia não impede uma cópia aqui porque é uma atribuição em vez de uma inicialização. No entanto, você ainda deve retornar por valor. Em C ++ 11, a atribuição é otimizada por algo diferente, chamado "mover semântica". Em C ++ 03, o código acima causa uma cópia e, embora em teoria um otimizador possa evitá-lo, na prática é muito difícil. Então
myvec = f()
, em vez de , em C ++ 03, você deve escrever isto:Existe outra opção, que é oferecer uma interface mais flexível ao usuário:
Você também pode oferecer suporte à interface baseada em vetor existente além disso:
Isso pode ser menos eficiente do que seu código existente, se seu código existente usar
reserve()
de uma forma mais complexa do que apenas uma quantia fixa inicial. Mas se o seu código existente basicamente chamarpush_back
o vetor repetidamente, esse código baseado em modelo deve ser tão bom.fonte
É hora de postar uma resposta sobre RVO , eu também ...
Se você retornar um objeto por valor, o compilador geralmente otimiza isso para que não seja construído duas vezes, uma vez que é supérfluo construí-lo na função como temporário e depois copiá-lo. Isso é chamado de otimização do valor de retorno: o objeto criado será movido em vez de ser copiado.
fonte
Um idioma comum pré-C ++ 11 é passar uma referência ao objeto que está sendo preenchido.
Então, não há cópia do vetor.
fonte
Se o compilador oferecer suporte a Otimização de valor de retorno nomeado ( http://msdn.microsoft.com/en-us/library/ms364057(v=vs.80).aspx ), você poderá retornar diretamente o vetor, desde que não haja:
NRVO otimiza o construtor de cópia redundante e chamadas de destruidor e, portanto, melhora o desempenho geral.
Não deve haver nenhuma diferença real em seu exemplo.
fonte
E se você quiser imprimir em main (), você deve fazer em um loop.
fonte
Por melhor que seja "retorno por valor", é o tipo de código que pode levar a um erro. Considere o seguinte programa:
O programa errôneo acima não indicará erros, mesmo se alguém usar as opções de relatórios GNU g ++ -Wall -Wextra -Weffc ++
Se você deve produzir um valor, o seguinte funcionaria no lugar de chamar vecFunc () duas vezes:
O acima também não produz objetos anônimos durante a iteração do loop, mas requer uma possível operação de cópia (que, como alguns observam, pode ser otimizada em algumas circunstâncias. Mas o método de referência garante que nenhuma cópia será produzida. Acreditando que o compilador será executar RVO não substitui a tentativa de construir o código mais eficiente possível. Se você pode questionar a necessidade de o compilador fazer RVO, você está à frente do jogo.
fonte
fonte