yohhoyの日記

技術的メモをしていきたい日記

nullptrキーワード

C++11で新たに導入されたnullptrキーワードおよびstd::nullptr_t型に関するメモ。

まとめ

  • nullptrキーワードはヌルポインタ定数を表すポインタリテラルC++03以前の値0, マクロNULLとは別に新たに追加された。
  • nullptrの型はstd::nullptr_t型と定義されるが、ユーザプログラム中でstd::nullptr_tを直接利用することはまず無い。
  • おまけ:C/C++言語の両者においてマクロNULLは処理系定義のヌルポインタ定数。

C++03以前からある特例ルール「値0はヌルポインタ定数としても扱う」に起因するオーバーロード問題を解消するために導入された。

void f(int);    // [A] int型
void f(char*);  // [B] char*型

// C++98/03
f(0);         // 0はint型リテラルとみなされ[A]が呼ばれる
f((char*)0);  // 明示的な型キャストを行えば[B]が呼ばれる
f((void*)0);  // NG: [A]と[B]でオーバーロード解決ができない
f(NULL);      // NULLの展開結果は整数型定数とみなされ[A]が呼ばれる

// C++11
f(0);        // [A]が呼ばれる
f(nullptr);  // [B]が呼ばれる
f(NULL);     // 処理系依存

なお、C++11標準でもヌルポインタ定数としての0およびNULLの意味は変更されておらず、両者の利用は特に非推奨(deprecated)とされていない。

#include <cstddef>
int* p1 = 0;     // OK
int* p2 = NULL;  // OK
int* p3 = nullptr;  // OK(C++11のみ)

nullptrキーワードとnullptr_t型

nullptrキーワードはポインタリテラル(pointer literal)を表しており、std::nullptr_t型のprvalue(≒右辺値)と定義される。std::nullptr_t型の値、つまりnullptrはヌルポインタ定数(null pointer constant)とされ、任意のポインタ型へと変換可能。またbool型の値falseへも変換可能(例:if文の条件式でも使える)。

なお、std::nullptr_t型は標準ヘッダ <cstddef> にてtypedefされているが、ユーザプログラム中ではstd::nullptr_t型を直接利用する機会は少ない*1。一部のライブラリコードではstd::nullptr_t型を利用するケースがある(例:std::unique_ptr, std::shared_ptr, std::functionクラステンプレートなど)。

N3337 2.14.7/p1, 3.9.1/p10, 4.12/p1(一部), 18.2/p9より引用。

1 The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t. [Note: std::nullptr_t is a distinct type that is neither a pointer type nor a pointer to member type; rather, a prvalue of this type is a null pointer constant and can be converted to a null pointer value or null member pointer value. See 4.10 and 4.11. -- end note]

10 A value of type std::nullptr_t is a null pointer constant (4.10). Such values participate in the pointer and the pointer to member conversions (4.10, 4.11). sizeof(std::nullptr_t) shall be equal to sizeof(void*).

1 (snip) A prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.

9 nullptr_t is defined as follows:

namespace std {
  typedef decltype(nullptr) nullptr_t;
}

The type for which nullptr_t is a synonym has the characteristics described in 3.9.1 and 4.10.

2012-10-29追記:The View from Aristeia: The Standard works in Circular Ways で、C++11標準のnullptrnullptr_tが循環定義されている点を言及。

nullptr vs. 0 vs. NULL

C++11標準におけるヌルポインタ定数 nullptr, 0, NULL の定義は下記通り。

nullptr
予約済みキーワード。任意のポインタ型に対するヌルポインタ定数を表すポインタリテラル
0
整数型(int)の定数値0、または任意のポインタ型に対するヌルポインタ定数として扱うことができる整数リテラル
NULL
標準ヘッダ <cstddef> にてヌルポインタ定数として定義される処理系定義のマクロ。*2 *3

N3337 4.10/p1, 18.2/p3より引用(下線部は強調)。

1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [Note: The resulting prvalue is not a null pointer value. -- end note]

3 The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).194
脚注194) Possible definitions include 0 and 0L, but not (void*)0.

関連URL

*1:N2431でも "We do not expect to see much direct use of nullptr_t in real programs." と言及。

*2:C言語のマクロ NULL も、ヌルポインタ定数を表す処理系定義のマクロと定義されている。"The macros are NULL which expands to an implementation-defined null pointer constant;"(7.17/p3)

*3:大抵のC++処理系では #define NULL 0 となっている。一方、大抵のC処理系では #define NULL ((void*)0) とされており、ヌルポインタと NULL に関する混乱に拍車をかけている。また、gccでは独自拡張キーワードを用いて #define NULL __null としている。