次のコードがなぜなのか興味があります。
#include <string>
int main()
{
std::string a = "ABCDEFGHIJKLMNO";
}
-O3
でコンパイルすると、次のコードが生成されます。
main: # @main
xor eax, eax
ret
(私は未使用のa
が必要ないことを完全に理解しているので、コンパイラは生成されたコードからそれを完全に省略することができます)
ただし、次のプログラム:
#include <string>
int main()
{
std::string a = "ABCDEFGHIJKLMNOP"; // <-- !!! One Extra P
}
利回り:
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"
同じ-O3
でコンパイルした場合。文字列が1バイト長いにもかかわらず、a
が未使用であることを認識しない理由がわかりません。
この質問は、gcc 9.1およびclang 8.0に関連しています(オンライン: https://gcc.godbolt.org/z/p1Z8Ns )。私の観察の他のコンパイラは、未使用の変数(ellcc)を完全に削除するためです。または、文字列の長さに関係なくコードを生成します。
受け入れられた回答は有効ですが、C++ 14以降では、実際にnew
およびdelete
がcanを呼び出すことが当てはまります。離れて最適化されます。 cppreferenceでこの難解な表現を参照してください。
新しい式では、置き換え可能な割り当て関数によって行われた...割り当てを省略できます。省略の場合、ストレージは、割り当て関数を呼び出さずにコンパイラーによって提供されます(これにより、未使用の新しい式を最適化することもできます)。
...
この最適化はnew-expressionsが使用される場合にのみ許可され、置換可能な割り当て関数を呼び出す他のメソッドは許可されないことに注意してください:
delete[] new int[10];
は最適化できますが、演算子delete(operator new(10));
はできません。
これにより、非常に長くても、コンパイラーはローカルのstd::string
を完全に削除できます。実際、libc ++を使用したclang ++ すでにこれを行っています (GodBolt)。libc++は__new
の実装で組み込み__delete
およびstd::string
を使用するため、これは「コンパイラーによって提供されるストレージ」です。したがって、次のようになります。
main():
xor eax, eax
ret
基本的に任意の長さの未使用の文字列を使用します。
GCCは対応していませんが、最近これに関するバグレポートを公開しました。リンクについては this SO answer を参照してください。