Why should I use a pointer rather than the object itself? Ask Question

Why should I use a pointer rather than the object itself? Ask Question

I'm coming from a Java background and have started working with objects in C++. But one thing that occurred to me is that people often use pointers to objects rather than the objects themselves, for example this declaration:

Object *myObject = new Object;

rather than:

Object myObject;

Or instead of using a function, let's say testFunc(), like this:

myObject.testFunc();

we have to write:

myObject->testFunc();

But I can't figure out why should we do it this way. I would assume it has to do with efficiency and speed since we get direct access to the memory address. Am I right?

ベストアンサー1

It's very unfortunate that you see dynamic allocation so often. That just shows how many bad C++ programmers there are.

In a sense, you have two questions bundled up into one. The first is when should we use dynamic allocation (using new)? The second is when should we use pointers?

The important take-home message is that you should always use the appropriate tool for the job. In almost all situations, there is something more appropriate and safer than performing manual dynamic allocation and/or using raw pointers.

Dynamic allocation

In your question, you've demonstrated two ways of creating an object. The main difference is the storage duration of the object. When doing Object myObject; within a block, the object is created with automatic storage duration, which means it will be destroyed automatically when it goes out of scope. When you do new Object(), the object has dynamic storage duration, which means it stays alive until you explicitly delete it. You should only use dynamic storage duration when you need it. That is, you should always prefer creating objects with automatic storage duration when you can.

The main two situations in which you might require dynamic allocation:

  1. You need the object to outlive the current scope - that specific object at that specific memory location, not a copy of it. If you're okay with copying/moving the object (most of the time you should be), you should prefer an automatic object.
  2. You need to allocate a lot of memory, which may easily fill up the stack. It would be nice if we didn't have to concern ourselves with this (most of the time you shouldn't have to), as it's really outside the purview of C++, but unfortunately, we have to deal with the reality of the systems we're developing for.

When you do absolutely require dynamic allocation, you should encapsulate it in a smart pointer or some other type that performs RAII (like the standard containers). Smart pointers provide ownership semantics of dynamically allocated objects. Take a look at std::unique_ptr and std::shared_ptr, for example. If you use them appropriately, you can almost entirely avoid performing your own memory management (see the Rule of Zero).

Pointers

ただし、動的割り当て以外にも、生のポインターにはより一般的な用途がありますが、ほとんどの場合、優先すべき代替手段があります。前と同様に、ポインターが本当に必要な場合を除き、常に代替手段を優先してください

  1. 参照セマンティクスが必要です。オブジェクトを渡す関数が特定のオブジェクト (そのコピーではなく) にアクセスできるようにしたいため、ポインターを使用してオブジェクトを渡したい場合があります (割り当て方法に関係なく)。ただし、ほとんどの場合、ポインターよりも参照型の方が適しています。これは、参照型が特にその目的のために設計されているためです。これは、上記の状況 1 のように、必ずしもオブジェクトの有効期間を現在のスコープを超えて延長することではありません。前と同様に、オブジェクトのコピーを渡しても問題ない場合は、参照セマンティクスは必要ありません。

  2. 多態性が必要です。関数を多態的に (つまり、オブジェクトの動的な型に従って) 呼び出すことができるのは、オブジェクトへのポインタまたは参照を介してのみです。それが必要な動作である場合は、ポインタまたは参照を使用する必要があります。繰り返しますが、参照を優先する必要があります。

  3. nullptrオブジェクトが省略されているときに を渡すことができるようにすることで、オブジェクトがオプションであることを表しますstd::optional。引数の場合は、デフォルトの引数または関数のオーバーロードを使用することをお勧めします。それ以外の場合は、この動作をカプセル化する型(C++17 で導入されました。以前の C++ 標準では を使用しますboost::optional) を使用することをお勧めします。

  4. コンパイル時間を短縮するために、コンパイル単位を分離したい場合。ポインタの便利な特性は、指し示す型の前方宣言のみが必要であることです(オブジェクトを実際に使用するには、定義が必要です)。これにより、コンパイルプロセスの一部を分離することができ、コンパイル時間を大幅に短縮できます。ピンプルの慣用句

  5. C ライブラリまたは C スタイルのライブラリとインターフェイスする必要があります。この時点で、生のポインターを使用する必要が生じます。最善の方法は、生のポインターを解放するのは、できるだけ最後の瞬間に限るようにすることです。たとえば、メンバーget関数を使用して、スマート ポインターから生のポインターを取得できます。ライブラリが割り当てを実行し、ハンドルを介して割り当てを解除する必要がある場合、多くの場合、オブジェクトを適切に割り当て解除するカスタム削除子を使用して、ハンドルをスマート ポインターでラップできます。

おすすめ記事