本Effective C++の中で、私は以下の一節を見た:
その結果、あなたが書く場合
class Empty{};
基本的に、これを書いた場合と同じです。
class Empty { public: Empty() { ... } Empty(const Empty& rhs) { ... } ~Empty() { ... } Empty& operator=(const Empty& rhs) { ... } // copy assignment operator };
次のコードにより、各関数が生成されます。
Empty e1; Empty e2(e1); e2 = e1;
しかし、上記のコードをコンパイルして作成された実行可能ファイルを逆アセンブルしたところ、そうではないことに気付きました。呼び出されている関数はありません。
主なアセンブリコードは次のとおりです。
00000000004006cd <main>:
4006cd: 55 Push %rbp
4006ce: 48 89 e5 mov %rsp,%rbp
4006d1: b8 00 00 00 00 mov $0x0,%eax
4006d6: 5d pop %rbp
4006d7: c3 retq
.text
セグメントに "Empty"という名前の関数はありません。
それでは、コンストラクターまたは空のクラスの割り当てを呼び出した後のコンパイラーの動作は実際には何でしょうか?本が言ったようにそれはいくつかの機能を生成しますか?もしそうなら、それらはどこに保存されますか?
関数は存在しますが、インライン化できます。
コンパイラーが関数をインライン化するとき、関数は何もしないことを認識し、コードは生成されません。
本が言っていることは、ある程度までは真実ですが、概念的な関数は、インラインおよび直接呼び出しのために、コンパイラーによって作成されます。
しかし、生成されたコードは空であるため、最適化コンパイラは関数の証拠を削除し(thisポインタを設定)、関数が直接呼び出されることはありません。
この本は、生成されたコードを実際に説明しようとしているのではなく、クラスを作成することの影響、およびクラスが通常の操作で生成する「隠された」関数を説明しています。
これらのメソッドは実際にクラスに対して生成されますが、「インライン」として生成されます。
class
が空の場合、それらはメンバーごとの実装であるため(たとえば、コピーコンストラクターはすべてのメンバーをコピーして構築します)、実際には何も行われず、インラインで表示されません。
ただし、これらのメソッドは自動的に実装されることを覚えておくことが非常に重要です。たとえば、コード
struct Foo {
char *buf;
Foo() : buf(new char[10]) {}
~Foo() { delete[] buf; }
};
コピーコンストラクターと割り当て用に自動的に生成されたコードが間違っていて、バッファーが複数削除されるため、バグが多いです。
何かが書かれたからではなく、notが書かれたためにバグがあり、これはトリッキーです。そのため、C++が自動的に書き込む内容を覚えておくことは非常に重要です。その実装が必要な場合は完璧ですが、そうでない場合は、正しい実装を提供するか、間違ったコードの作成または使用を禁止して修正します。
あなたと本は、抽象化のさまざまなレベルからこの状況に来ています。
本書では、「生成された」という用語を使用して、コンパイラーによって抽象C++プログラムに暗黙的に定義されているC++関数を指します。これは絶対に起こります。
あなたはそれを翻訳されたプログラムでの実際の機械語コードの実際の生成を意味すると解釈しています。それが意味することではありません。元の抽象プログラムのセマンティクスが維持されている限り、実際のマシンコードの生成は常にコンパイラーの気まぐれの影響を受けます。
そのため、この本は間違いなく間違いではありませんが、わかりやすくするために別の単語を使用したと思います。標準的な用語にこだわることは決して害にはなりません。