Eu estava lendo "The C ++ Programming Language" de Stroustrup, onde ele diz que de duas maneiras de adicionar algo a uma variável
x = x + a;
e
x += a;
Ele prefere +=
porque provavelmente é melhor implementado. Acho que ele quer dizer que funciona mais rápido também.
Mas é mesmo? Se depender do compilador e outras coisas, como faço para verificar?
c++
performance
operators
Chiffa
fonte
fonte
Respostas:
Qualquer valor de compilador o seu sal vai gerar exatamente a mesma seqüência de linguagem de máquina para ambas as construções para qualquer tipo built-in (
int
,float
, etc), desde que a declaração é realmente tão simples comox = x + a;
e otimização está habilitado . (Notavelmente, o GCC-O0
, que é o modo padrão, realiza anti-otimizações , como inserir armazenamentos completamente desnecessários na memória, a fim de garantir que os depuradores sempre possam encontrar valores de variáveis.)Se a declaração for mais complicada, porém, eles podem ser diferentes. Suponha que
f
seja uma função que retorna um ponteiro, entãoliga
f
apenas uma vez, enquantochama duas vezes. Se
f
tiver efeitos colaterais, um dos dois estará errado (provavelmente o último). Mesmo sef
não tiver efeitos colaterais, o compilador pode não ser capaz de eliminar a segunda chamada, portanto, a última pode ser mais lenta.E como estamos falando sobre C ++ aqui, a situação é totalmente diferente para tipos de classes que sobrecarregam
operator+
eoperator+=
. Sex
for esse tipo, então - antes da otimização - sex += a
traduz emx.operator+=(a);
Considerando que se
x = x + a
traduz emauto TEMP(x.operator+(a)); x.operator=(TEMP);
Agora, se a classe for escrita corretamente e o otimizador do compilador for bom o suficiente, ambos acabarão gerando a mesma linguagem de máquina, mas não é uma coisa certa como é para tipos internos. Provavelmente é nisso que Stroustrup está pensando quando incentiva o uso de
+=
.fonte
expr
avar
évar+=expr
e escrevê-lo para o outro lado vai confundir os leitores.*f() = *f() + a;
talvez queira dar uma boa olhada no que você realmente está tentando alcançar ...1
é uma constante,a
pode ser volátil, um tipo definido pelo usuário ou qualquer outra coisa. Completamente diferente. Na verdade, não entendo como isso foi encerrado.Você pode verificar olhando para a desmontagem, que será a mesma.
Para tipos básicos , ambos são igualmente rápidos.
Esta é a saída gerada por uma compilação de depuração (ou seja, sem otimizações):
a += x; 010813BC mov eax,dword ptr [a] 010813BF add eax,dword ptr [x] 010813C2 mov dword ptr [a],eax a = a + x; 010813C5 mov eax,dword ptr [a] 010813C8 add eax,dword ptr [x] 010813CB mov dword ptr [a],eax
Para tipos definidos pelo usuário , onde você pode sobrecarregar
operator +
eoperator +=
, depende de suas respectivas implementações.fonte
a
for 1 ex
forvolatile
o compilador poderia gerarinc DWORD PTR [x]
. Isso é lento.operator +
não fazer nada eoperator +=
calcular o número 100000º primo e depois retornar. Claro, isso seria uma coisa estúpida de se fazer, mas é possível.++x
etemp = x + 1; x = temp;
, então provavelmente ele deve ser escrito em assembly em vez de c ++ ...Sim! É mais rápido escrever, ler e descobrir, para o último caso
x
possa ter efeitos colaterais. Portanto, é no geral mais rápido para os humanos. O tempo humano em geral custa muito mais do que o tempo do computador, então deve ser sobre isso que você está perguntando. Direito?fonte
Realmente depende do tipo de xea e da implementação de +. Para
o compilador deve criar um T temporário para conter o valor de x + a enquanto o avalia, que pode então atribuir a x. (Não pode usar x ou a como área de trabalho durante esta operação).
Para x + = a, não precisa de um temporário.
Para tipos triviais, não há diferença.
fonte
A diferença entre
x = x + a
ex += a
é a quantidade de trabalho que a máquina tem que passar - alguns compiladores podem (e geralmente fazem) otimizá-la, mas geralmente, se ignorarmos a otimização por um tempo, o que acontece é que no trecho de código anterior, o a máquina deve pesquisar o valorx
duas vezes, enquanto na última, essa pesquisa precisa ocorrer apenas uma vez.No entanto, como mencionei, hoje a maioria dos compiladores são inteligentes o suficiente para analisar a instrução e reduzir as instruções de máquina resultantes necessárias.
PS: Primeira resposta no Stack Overflow!
fonte
Como você rotulou este C ++, não há como saber a partir das duas declarações que você postou. Você precisa saber o que é 'x' (é um pouco como a resposta '42'). Se
x
for um POD, não fará muita diferença. No entanto, sex
for uma classe, pode haver sobrecargas para os métodosoperator +
eoperator +=
que podem ter comportamentos diferentes que levam a tempos de execução muito diferentes.fonte
Se você disser
+=
que está tornando a vida muito mais fácil para o compilador. Para que o compilador reconheça quex = x+a
é o mesmo quex += a
, o compilador deveanalise o lado esquerdo (
x
) para ter certeza de que não há efeitos colaterais e sempre se refere ao mesmo valor l. Por exemplo, pode serz[i]
, e tem que garantir que ambosz
ei
não mudem.analise o lado direito (
x+a
) e certifique-se de que é um somatório, e que o lado esquerdo ocorre uma vez e apenas uma vez no lado direito, embora possa ser transformado, como emz[i] = a + *(z+2*0+i)
.Se o que você quer dizer é adicionar
a
ax
, o redator do compilador agradece quando você apenas diz o que quer dizer. Dessa forma, você não está exercitando a parte do compilador que seu escritor espera que ele / ela tem todos os bugs fora de, e que não realmente tornar a vida mais fácil para você, a menos que você honestamente não pode obter a cabeça para fora do modo Fortran.fonte
Para um exemplo concreto, imagine um tipo de número complexo simples:
struct complex { double x, y; complex(double _x, double _y) : x(_x), y(_y) { } complex& operator +=(const complex& b) { x += b.x; y += b.y; return *this; } complex operator +(const complex& b) { complex result(x+b.x, y+b.y); return result; } /* trivial assignment operator */ }
Para o caso a = a + b, ele tem que fazer uma variável temporária extra e então copiá-la.
fonte
Você está fazendo a pergunta errada.
É improvável que isso impulsione o desempenho de um aplicativo ou recurso. Mesmo se fosse, a maneira de descobrir é analisar o código e saber como ele o afeta com certeza. Em vez de se preocupar nesse nível com o que é mais rápido, é muito mais importante pensar em termos de clareza, correção e legibilidade.
Isso é especialmente verdadeiro quando você considera que, mesmo que seja um fator de desempenho significativo, os compiladores evoluem com o tempo. Alguém pode descobrir uma nova otimização e a resposta certa hoje pode se tornar errada amanhã. É um caso clássico de otimização prematura.
Isso não quer dizer que o desempenho não tenha importância alguma ... Apenas que é a abordagem errada para atingir seus objetivos de desempenho. A abordagem certa é usar ferramentas de criação de perfil para aprender onde seu código está realmente gastando seu tempo e, portanto, onde concentrar seus esforços.
fonte
Acho que isso deve depender da máquina e de sua arquitetura. Se sua arquitetura permitir endereçamento indireto de memória, o redator do compilador PODE usar este código (para otimização):
mov $[y],$ACC iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"
Visto que,
i = i + y
pode ser traduzido para (sem otimização):Dito isso, outras complicações, como se
i
é um ponteiro de retorno de função, etc., também devem ser consideradas. A maioria dos compiladores de nível de produção, incluindo GCC, produzem o mesmo código para ambas as instruções (se forem inteiros).fonte
Não, as duas maneiras são tratadas da mesma forma.
fonte