C++のnullptrとは何か?NULLとの違いと使い方をわかりやすく解説
C++11で導入されたnullptrは、ポインタリテラルを表すキーワードです。nullptrは型std::nullptr_tのprvalue(純右辺値)であり、任意のポインタ型やメンバポインタ型のヌルポインタ値へ暗黙的に変換できるという特性を持っています。本記事では、具体的なプログラム例を通じて、nullptrの概念と従来のNULLとの違いを詳しく解説します。
NULLを使った場合の問題点
まず、従来のNULLを使用した場合にどのような問題が発生するのか、次のサンプルコードで確認してみましょう。
サンプルコード
#include<iostream>
using namespace std;
int my_func(int N){ // int型引数を取る関数
cout << "Calling function my_func(int)";
}
int my_func(char* str) { // char*型引数を取るオーバーロード関数
cout << "calling function my_func(char *)";
}
int main() {
my_func(NULL); // my_func(char *)が呼ばれるはずだが、コンパイルエラーになる
}実行結果
[Error] call of overloaded 'my_func(NULL)' is ambiguous [Note] candidates are: [Note] int my_func(int) [Note] int my_func(char*)
このプログラムでは、どこに問題があるのでしょうか。原因は、NULLが通常(void*)0として定義されていることにあります。NULLは整数型へも変換が許可されているため、コンパイラから見るとmy_func(NULL)という呼び出しが「int型の引数に変換すべきか」「char*型の引数に変換すべきか」を判断できず、曖昧(ambiguous)になってしまうのです。
nullptrを使った解決策
そこで、NULLの代わりにnullptrを使用すると、同じコードでも期待どおりに動作します。
サンプルコード
#include<iostream>
using namespace std;
int my_func(int N){ // int型引数を取る関数
cout << "Calling function my_func(int)";
}
int my_func(char* str) { // char*型引数を取るオーバーロード関数
cout << "calling function my_func(char *)";
}
int main() {
my_func(nullptr); // 明確にmy_func(char *)が呼び出される
}実行結果
calling function my_func(char *)
今度はコンパイルエラーが発生せず、意図したとおりmy_func(char *)が呼び出されました。これは、nullptrがポインタ型として明確な型情報を持っているため、オーバーロードの解決時に曖昧さが生じないからです。
nullptrの特徴まとめ
nullptrは、これまでNULLが使われていたすべての場所で利用できます。NULLと同様に、nullptrも任意のポインタ型へ変換可能です。しかし大きな違いとして、nullptrはNULLのように整数型へ暗黙的に変換することはできません。この特性により、意図しない型変換によるバグや曖昧な関数呼び出しを防ぐことができます。
現代のC++プログラミングでは、ヌルポインタを表す際にはマクロのNULLではなく、型安全なnullptrを使用することが強く推奨されています。
-
C++で範囲加算を効率的に解く方法 ― 差分配列(いもす法)の活用
問題概要 サイズnの整数配列が与えられ、すべての要素が0で初期化されているとします。さらに値kが与えられ、k回の更新操作を行います。各操作は [startIndex, endIndex, inc] という3つ組で表され、部分配列 A[startIndex ... endIndex](startIndexとendIndexを含む)の各要素に inc を加算します。k回の操作をすべて実行した後の、変更後の配列を求めるのがこの問題です。 例えば、入力が length = 5、updates = [[1,3,2],[2,4,3],[0,2,-2]] の場合、出力は [-2, 0, 3, 5, 3]
-
C++で点集合の線対称(ラインリフレクション)を判定するアルゴリズム
問題概要2次元平面上にn個の点が与えられます。このとき、y軸に平行な直線で全ての点を鏡映(反射)した結果が、元の点集合と完全に一致するような直線が存在するかどうかを判定します。言い換えれば、ある直線を対称軸として全ての点を反転させたとき、反転後の点の集合が元の集合と同一になるかを確認する問題です。例えば、入力が points = [[1,1],[-1,1]] の場合を考えてみましょう。この場合、x = 0 の直線(y軸)を対称軸とすると、点 (1,1) は (-1,1) へ、(-1,1) は (1,1) へと移ります。点集合全体としては変化がないため、出力は true となります。解法のポイン