ポインタと参照の構文と一般的なセマンティクスは理解していますが、API で参照とポインタのどちらを使用するのが適切かをどのように判断すればよいでしょうか?
当然、状況によってはどちらか一方 (operator++
参照引数が必要) が必要になりますが、一般的には、変数が破壊的に渡されることが構文上明らかなので、ポインター (および const ポインター) を使用する方がよいと思います。
例えば次のコード:
void add_one(int& n) { n += 1; }
void add_one(int* const n) { *n += 1; }
int main() {
int a = 0;
add_one(a); // Not clear that a may be modified
add_one(&a); // 'a' is clearly being passed destructively
}
ポインターを使用すると、何が起こっているかが常に (より) 明らかになります。したがって、明確さが大きな懸念事項となる API などでは、参照よりもポインターの方が適切ではないでしょうか。つまり、参照は必要な場合にのみ使用すべきということですか (例operator++
)。どちらか一方にパフォーマンス上の懸念はありますか。
編集(古い)
値を許可し、生の配列を扱うこと以外にNULL
、選択は個人の好みに帰着するようです。私は以下の回答を受け入れました。Google の C++ スタイル ガイドなぜなら、彼らは「参照は値の構文を持ちながらポインターのセマンティクスを持つため、混乱を招く可能性がある」という見解を示しているからです。
NULL であってはならないポインタ引数をサニタイズするために必要な追加作業 (add_one(0)
ポインタ バージョンを呼び出して実行時に中断するなど) のため、構文の明確さが失われるのは残念ですが、オブジェクトが存在する必要がある場所では参照を使用することは保守性の観点からは理にかなっています。
ベストアンサー1
可能な場合は参照を使用し、必要な場合はポインタを使用します。
できないまでポインタを避けてください。
その理由は、ポインタを使用すると、他の構成要素よりも追跡や読み取りが難しくなり、安全性が低下し、操作がはるかに危険になるためです。
したがって、経験則としては、他に選択肢がない場合にのみポインターを使用するのがよいでしょう。
たとえば、関数が場合によっては戻る可能性があり、そうすることが想定される場合、オブジェクトへのポインタを返すことは有効なオプションですnullptr
。ただし、より良いオプションは、次のようなものを使用することです。std::optional
(C++17が必要です。それ以前はboost::optional
)。
もう 1 つの例は、特定のメモリ操作に生のメモリへのポインタを使用することです。これは、コード ベース全体の危険な部分を制限できるように、コードの非常に狭い部分に隠して局所化する必要があります。
あなたの例では、次の理由により、ポインタを引数として使用しても意味がありません。
- 引数として提供した場合
nullptr
、未定義の動作が発生します。 - 参照属性バージョンでは、(簡単に見つけられるトリックなしでは) 1 の問題は発生しません。
- 参照属性バージョンはユーザーにとって理解しやすいもので、null になる可能性のあるものではなく、有効なオブジェクトを提供する必要があります。
関数の動作が特定のオブジェクトの有無にかかわらず機能する必要がある場合、ポインターを属性として使用すると、nullptr
引数として渡すことができ、関数にとって問題ないことが示されます。これは、ユーザーと実装の間の一種の契約です。