ポインターにはいくつかの問題があります。
- エイリアシング異なる名前/変数を使用してオブジェクトの値を変更する可能性。
- 非局所性宣言されているコンテキストとは異なるコンテキストでオブジェクト値を変更する可能性(これは、参照渡しの引数でも発生します)。
- ライフタイムの不一致ポインターのライフタイムは、ポインターが指すオブジェクトのライフタイムと異なる場合があり、無効な参照(SEGFAULTS)またはガベージにつながる可能性があります。
- ポインタ演算。一部のプログラミング言語では、ポインターを整数として操作できます。つまり、ポインターはどこでも指すことができます(バグが存在する場合の最も予期しない場所を含む)。ポインター演算を正しく使用するには、プログラマーが指すオブジェクトのメモリーサイズを認識している必要があります。これについては、さらに考慮する必要があります。
- 型キャストある型から別の型にポインターをキャストする機能により、意図したものとは異なるオブジェクトのメモリを上書きできます。
そのため、プログラマーはポインターを使用するとき、より徹底的に考える必要があります(抽象化の2つのレベルについては知りません)。これは、初心者が犯す典型的な間違いの例です。
Pair* make_pair(int a, int b)
{
Pair p;
p.a = a;
p.b = b;
return &p;
}
上記のようなコードは、ポインターの概念を持たない言語では完全に合理的であることに注意してください。関数型プログラミング言語やガベージコレクション(Java、Python)のある言語のように、名前(参照)、オブジェクト、値のいずれかです。
再帰関数の難しさは、十分な数学的背景のない人々(再帰性が一般的で必要な知識)が、関数が以前に呼び出された回数に応じて異なる動作をすると考えてアプローチしようとするときに発生します。再帰関数があるため、その問題を悪化さ確かにできている方法で作成されますが、その方法を考える必要がありますそれらを理解します。
データ構造がその場で変更されるRed-Black Treeの手続き型実装のように、ポインタが渡される再帰関数を考えてください。それは機能的な対応者より考えるのがより難しいものです。
質問では言及されていませんが、初心者が困難に感じる他の重要な問題は並行性です。
他の人が述べたように、いくつかのプログラミング言語の構成要素には、概念的ではない追加の問題があります。理解できたとしても、それらの構成要素の単純で正直な間違いはデバッグが非常に困難です。