Question:なぜオブジェクトそのものよりもポインターを使う方が良いのですか?
私はJavaプログラマーで、最近C++でオブジェクトを使うことを学び始めました。それは、なぜ人々はオブジェクトそのものではなく、オブジェクトへのポインタを使いたがるのかということです。例えば
Object *myObject = new Object;
代わりに:オブジェクト myObject;
関数を使う場合も同じで、testFunc()という関数があったとします:
myObject.testFunc();
でも、一般的にはこう呼ばれます:
myObject->testFunc();
しかし、なぜこのようなことをするのかわかりません。メモリアドレスに直接アクセスすることで、効率と実行速度が向上するからではないでしょうか。私の理解は正しいでしょうか?
***答えは?
残念なことに、動的アロケーションについて書かれた本の多くは、そのようなものではありません。これは、単にC++に習熟していないプログラマーがたくさん存在するということを意味しているとしか思えません。ある意味で、この問題は2つの小さな問題に分けることができます。つは、いつダイナミック・アロケーションを使うべきか?もう1つは、いつポインタを使うべきか?
適切なツールを使うことは、通常、良い仕事をするための鍵です。ほとんどの場合、通常の動的アロケーションや生のポインタを使うよりも、より適切で安全な方法が存在します。
ダイナミックアロケーション
この問題では、2つの方法でオブジェクトを作成しました。この2つの方法の主な違いは、オブジェクトの保存期間です。Object myObject;というコードを実行すると、オブジェクトは自動変数として作成され、スコープ外に出ると自動的に破棄されます。一方、このように new Object() を使用した場合、オブジェクトが保持するメモリは動的に確保されるため、delete() メソッドを呼び出すまでオブジェクトは破棄されず、常に存在することになります。動的に確保されたメモリを扱う必要がある場合は、動的に確保されたメソッドのみを使用すべきです。つまり、動的に確保されたメモリを使用できる場合は、自動変数を使用しないでください。
動的割り当てが使用される2つの一般的な状況を示します:
1. スコープ外でもオブジェクトが存在するようにしたい場合 - そして、オブジェクトのコピーではなく、実際にそのメモリに格納されているオブジェクトでありたい場合。オブジェクトのコピーを使ったり、移動させたりしても構わないのであれば、自動保存メソッドを使うべきです。
2.大量のメモリが必要な場合、この状況は簡単にスタックオーバーフローにつながります。もちろん、これがまったく問題にならなければいいのですが。これは明らかにC++の管轄外ですが、残念ながら、この種の問題を抱えるシステム開発の現実に対処しなければなりません。
ダイナミック・アロケーションを使用する必要がある場合は、スマート・ポインタを使用するか、RAIIの特性を持つ他の型にカプセル化する必要があります。スマート・ポインタは、動的にメモリを割り当てるオブジェクトの所有権セマンティクスを提供します。適切に使用すれば、基本的にメモリを自分で管理する必要はありません(「Rule of Zero記事を参照してください)。
指針
実際、メモリを動的に割り当てる以外にもポインタの使い道はたくさんありますが、そのほとんどはポインタよりも優れた代替手段があります。先ほども言いましたが、ポインタは必要なとき以外は使わないようにしましょう。
リファレンスが必要な状況:呼び出したい関数がカレント・オブジェクト自体へのアクセスを必要とする場合があり、その場合、引数として渡されるポインタを使用する必要があります。しかし、ほとんどの場合、ポインタよりもリファレンスを使ったほうがよいでしょう。注意点として、ここでは上記のようにオブジェクトのライフサイクルを拡張する必要はありません。すでに述べたように、オブジェクトのコピーを使っても構わないのであれば、もう参照を使う必要はありません。
ポリモーフィズムを使う必要がある状況: 通常、ポリモーフィズムはオブジェクトへのポインタか参照を通してしか実装できません。もしそうしたいのであれば、ポインタか参照を使う必要があります。繰り返しますが、ポインタの方が望ましいです。
NULLポインタを渡してオブジェクトを実装することは、そのオブジェクトが無視可能である場合にはオプションのプロパティです。パラメータであれば、デフォルトのパラメータを使うか、関数のオーバーロードメソッドを使うことをお勧めします。そうでなければ、boost::optional(またはstd::optional)のような、この振る舞いをカプセル化した型を選ぶべきです。
CまたはCライクなスタイルのライブラリーのインターフェースを呼び出したいとき:この場合、ポインターを操作しなければなりません。唯一できることは、ポインタを使用しないときは必ず解放することです。また、スマート・ポインタを通してメンバ関数を呼び出すなど、元のポインタを操作することもできます。呼び出されたライブラリがあなたのために領域を確保し、ハンドル経由で解放することを望むなら、ハンドルをスマートポインタでラップし、カスタムデストラクタを使ってメモリを解放することは理にかなっています。




