2. 生のポインタは使わないで!
- char *やvoid *などの生のポインタは使わない。
- ポインタを使いたければスマートポインタで。
これってキツくないですか? C言語といえばポインタ、ポインタといえばC言語でしょう。C++になってクラスが導入されましたけど、インスタンスを使うときにはやはりポインタが大活躍しました。これを使うなとは……。
でもよく読んでください! ポインタを使うなではなくて、「生の」って付いているじゃないですか。そうか、生のポインタを使うなってだけで、ポインタそのものは使えるのですね、少し安心しました。ところで「生のポインタ」って何でしょうか?
生のポインタとは、C言語からの伝統でもある、「char *」などです。生のポインタという表現が文字通り生々しいなら、「剥き出しのポインタ」とでもしましょうか(余計に生々しくなった?)。表現は置いておいて、生のポインタの問題点をおさらいしましょう。リスト3のプログラムを実行すると、エラーになって異常終了してしまいます。
#include <iostream>
using namespace std;
int main()
{
char *p;
*p = 'A';
cout << *p << "\n";
// zsh: segmentation fault ./dangling
return 0;
}
char型のポインタpが宣言されてますけど、初期化されていません。ここに「*p」を使って'A'を入れようとしていますが、明らかにダメです。pがどこを指しているか分からない、すなわちダングリングの状態だからです。では初期化すればいいんでしょうか?pを宣言する行を書き換えてみます。
…略… char *p = NULL; …略… cout << *p << "\n"; // zsh: segmentation fault ./dangling_2
pは初期化はされていますが、NULLという値(これも実際のところどういう値なのかは分からない)を使っているので、そこが安全な場所であるかは分かりません。たいていの場合はイケない場所なので、これも'\0'を代入したとたんにおかしなことになります。ダングリングであることには変わりません。なお、Modern C++ではNULLも使ってはいけないことになっています。「どこも指していない」ことを明示するnullptrというものがあるようです。
要は、生のポインタを使う限り、ポインタで指す場所が有効であるかということは、プログラマが責任を持って保証してあげなければならないということです。これは、バグを防ぐためにも必要なことですが、プログラマにとって大きな負担ともなります。どうせなら、生のポインタは使えなくなってくれればいいのに!ということで、前節のnew演算子です。new演算子を使った結果はやはり生のポインタでしたが、スマートポインタというものを使うことで、生のポインタの使用を避けて、メモリの確保と解放も自動でやってくれます。スマートポインタについてもどこかの回で紹介します。
