私はさまざまな初期化方法を試し、さまざまなユースケースとパフォーマンスへの影響に対してそれらが提供する開発者エクスペリエンスを評価していました。その過程で、2つのコードスニペットを作成しました。1つは直接初期化を使用し、もう1つは初期化子リストを使用します。
直接:
class C {
public:
char* x;
C() : x(new char[10] {'0','1'}) {}
};
C c;
イニシャライザリスト:
#include <utility>
#include <algorithm>
class C {
public:
char* x;
C(std::initializer_list<char> il) {
x = new char[10];
std::copy(il.begin(), il.end(), x);
}
};
C c = {'0','1'};
std::initializer_list
同じアセンブリを生成することを期待していました。なぜそれが悪化するのか(より複雑に見える)は理解できますが、実際に悪化した場合は、ここでまったく異なる質問をしていました。より少ない命令でより良いコードを生成するのを見たときの驚きを想像してみてください!
上記のスニペットでgodboltへのリンク- https://godbolt.org/z/i3XZ_K
直接:
_GLOBAL__sub_I_c:
sub rsp, 8
mov edi, 10
call operator new[](unsigned long)
mov edx, 12592
mov WORD PTR [rax], dx
mov QWORD PTR [rax+2], 0
mov QWORD PTR c[rip], rax
add rsp, 8
ret
c:
.zero 8
イニシャライザリスト:
_GLOBAL__sub_I_c:
sub rsp, 8
mov edi, 10
call operator new[](unsigned long)
mov edx, 12592
mov QWORD PTR c[rip], rax
mov WORD PTR [rax], dx
add rsp, 8
ret
c:
.zero 8
アセンブリは、mov QWORD PTR [rax+2], 0
一見ヌル文字でchar配列が終了しているように見える追加の命令を除いて、ほとんど同じです。ただし、IIRCのみの文字列リテラル(など"01"
)は、char配列リテラルではなく、null文字で自動的に終了します。
生成されたコードが異なる理由と、直接のケースを改善するために私ができること(可能であれば)についての洞察をいただければ幸いです。
また、x86アセンブリに関しては初心者なので、明らかな何かが足りない場合はお知らせください。
編集:文字を追加した場合にのみ悪化します-https://godbolt.org/z/e8Gys_
2つのサンプルコードスニペットは同じ効果を持ちません。
new char[10] {'0','1'}
この集約-新しいchar
配列を初期化します。つまり、中括弧で囲まれた初期化子リストで初期化子が指定されていない配列のすべての要素がゼロに初期化されます。
x = new char[10];
これにより、新しい配列の要素が値に設定されたり、
std::copy(il.begin(), il.end(), x);
で実際に指定されている要素のみを設定しますstd::initializer_list
。
したがって、最初のバージョンでは、コンパイラーは、初期化子が指定されていないすべての要素がゼロに設定されることを保証する必要がありますが、2番目のバージョンではこれらの値はそのままにしておくことができます。
新しい式で配列を直接部分的に初期化する方法はありません。しかし、2番目の例の動作の明らかな再現は次のようになります
C() : x(new char[10]) {
constexpr char t[]{'0','1'};
std::copy(std::begin(t), std::end(t), x);
}
ただし、実際には、new
とにかく直接使用するべきではありません。代わりに使用しstd::vector<char>
、std::array<char, 10>
、std::string
またはstd::unique_ptr<char[]>
具体的なユースケースに応じました。これらはすべて、new
原因となる生涯の問題を回避します。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加