Je suis curieux de savoir pourquoi le morceau de code suivant:
#include <string>
int main()
{
std::string a = "ABCDEFGHIJKLMNO";
}
une fois compilé avec -O3
donne le code suivant:
main: # @main
xor eax, eax
ret
(Je comprends parfaitement qu'il n'y a pas besoin de a
inutilisé pour que le compilateur puisse entièrement l'omettre du code généré)
Cependant le programme suivant:
#include <string>
int main()
{
std::string a = "ABCDEFGHIJKLMNOP"; // <-- !!! One Extra P
}
rendements:
main: # @main
Push rbx
sub rsp, 48
lea rbx, [rsp + 32]
mov qword ptr [rsp + 16], rbx
mov qword ptr [rsp + 8], 16
lea rdi, [rsp + 16]
lea rsi, [rsp + 8]
xor edx, edx
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long)
mov qword ptr [rsp + 16], rax
mov rcx, qword ptr [rsp + 8]
mov qword ptr [rsp + 32], rcx
movups xmm0, xmmword ptr [rip + .L.str]
movups xmmword ptr [rax], xmm0
mov qword ptr [rsp + 24], rcx
mov rax, qword ptr [rsp + 16]
mov byte ptr [rax + rcx], 0
mov rdi, qword ptr [rsp + 16]
cmp rdi, rbx
je .LBB0_3
call operator delete(void*)
.LBB0_3:
xor eax, eax
add rsp, 48
pop rbx
ret
mov rdi, rax
call _Unwind_Resume
.L.str:
.asciz "ABCDEFGHIJKLMNOP"
lorsqu'il est compilé avec le même -O3
. Je ne comprends pas pourquoi il ne reconnaît pas que le a
est toujours inutilisé, même si la chaîne fait un octet de plus.
Cette question est pertinente pour gcc 9.1 et clang 8.0, (en ligne: https://gcc.godbolt.org/z/p1Z8Ns ) car d'autres compilateurs dans mon observation suppriment entièrement la variable inutilisée (ellcc) ou générer du code pour cela quelle que soit la longueur de la chaîne.
Bien que la réponse acceptée soit valide, depuis C++ 14, il est en fait vrai que les appels new
et delete
peuvent être optimisé loin. Voir cette formulation obscure sur cppreference:
Les nouvelles expressions sont autorisées à éliminer ... les allocations effectuées via des fonctions d'allocation remplaçables. En cas d'élision, le stockage peut être fourni par le compilateur sans faire appel à une fonction d'allocation (cela permet également d'optimiser la nouvelle expression inutilisée).
...
Notez que cette optimisation n'est autorisée que lorsque de nouvelles expressions sont utilisées, pas d'autres méthodes pour appeler une fonction d'allocation remplaçable:
delete[] new int[10];
Peut être optimisé, mais l'opérateurdelete(operator new(10));
ne peut pas.
Cela permet en fait aux compilateurs de supprimer complètement votre std::string
Local même s'il est très long. En fait - clang ++ avec libc ++ fait déjà cela (GodBolt), car libc ++ utilise les inserts __new
Et __delete
Dans son implémentation de std::string
- c'est "le stockage fourni par le compilateur". Ainsi, nous obtenons:
main():
xor eax, eax
ret
avec une chaîne inutilisée de n'importe quelle longueur.
GCC ne fait pas mais j'ai récemment ouvert des rapports de bogues à ce sujet; voir this SO answer pour les liens.