ポインタ宣言
ポインタまたはメンバへのポインタ型の変数を宣言します。
目次 |
[編集] 構文
ポインタ宣言は、その宣言子が以下の形式を持つ単純な宣言です。
* attr (optional) cv (optional) declarator |
(1) | ||||||||
nested-name-specifier * attr (optional) cv (optional) declarator |
(2) | ||||||||
S で決定される型の C の非静的メンバへのポインタとして D を宣言します。| nested-name-specifier | - | 名前とスコープ解決演算子 :: のシーケンス |
| attr | - | (C++11以降) 属性のリスト |
| cv | - | 宣言されるポインタに適用されるconst/volatile修飾子 (指し示す型に適用される修飾子は宣言指定子シーケンスの一部です) |
| declarator (宣言子) | - | 参照宣言子以外のあらゆる宣言子 (参照へのポインタは存在しません)。別のポインタ宣言子でも構いません (ポインタへのポインタは許可されます) |
参照へのポインタやビットフィールドへのポインタは存在しません。通常、詳細な説明なしに「ポインタ」という言葉が言及される場合、(非静的)メンバへのポインタは含まれません。
[編集] ポインタ
ポインタ型のすべての値は、以下のいずれかです。
オブジェクトを指すポインタは、オブジェクトが占めるメモリの最初のバイトのアドレスを表します。オブジェクトの終端を超えたポインタは、オブジェクトが占めるストレージの終端の後のメモリの最初のバイトのアドレスを表します。
同じアドレスを表す2つのポインタが、それでも異なる値を持つ場合があることに注意してください。
struct C { int x, y; } c; int* px = &c.x; // value of px is "pointer to c.x" int* pxe= px + 1; // value of pxe is "pointer past the end of c.x" int* py = &c.y; // value of py is "pointer to c.y" assert(pxe == py); // == tests if two pointers represent the same address // may or may not fire *pxe = 1; // undefined behavior even if the assertion does not fire
無効なポインタ値の逆参照と、無効なポインタ値を解放関数に渡すことは未定義の動作です。無効なポインタ値のその他の使用は実装定義の動作です。一部の実装では、無効なポインタ値をコピーするとシステム生成の実行時障害が発生すると定義する場合があります。
[編集] オブジェクトへのポインタ
オブジェクトへのポインタは、別のポインタ型を含む任意のオブジェクト型の式に適用されるアドレス演算子の戻り値で初期化できます。
int n; int* np = &n; // pointer to int int* const* npp = &np; // non-const pointer to const pointer to non-const int int a[2]; int (*ap)[2] = &a; // pointer to array of int struct S { int n; }; S s = {1}; int* sp = &s.n; // pointer to the int that is a member of s
ポインタは組み込みの逆参照演算子 (単項 operator*) のオペランドとして現れることがあり、これは指し示すオブジェクトを識別する左辺値式を返します。
int n; int* p = &n; // pointer to n int& r = *p; // reference is bound to the lvalue expression that identifies n r = 7; // stores the int 7 in n std::cout << *p; // lvalue-to-rvalue implicit conversion reads the value from n
クラスオブジェクトへのポインタは、メンバアクセス演算子 operator-> および operator->* の左オペランドとしても現れることがあります。
配列からポインタへの暗黙の変換により、配列の最初の要素へのポインタは配列型の式で初期化できます。
int a[2]; int* p1 = a; // pointer to the first element a[0] (an int) of the array a int b[6][3][8]; int (*p2)[3][8] = b; // pointer to the first element b[0] of the array b, // which is an array of 3 arrays of 8 ints
派生クラスから基底クラスへのポインタの暗黙の変換により、基底クラスへのポインタは派生クラスのアドレスで初期化できます。
struct Base {}; struct Derived : Base {}; Derived d; Base* p = &d;
Derived がポリモーフィックである場合、そのようなポインタは仮想関数呼び出しを行うために使用できます。
配列の要素へのポインタに対して、特定の加算、減算、インクリメント、デクリメント演算子が定義されています。そのようなポインタはLegacyRandomAccessIterator要件を満たし、C++ライブラリのアルゴリズムが生の配列で動作することを可能にします。
特定の状況下では、オブジェクトへのポインタに対して比較演算子が定義されます。同じアドレスを表す2つのポインタは等しく比較され、2つのヌルポインタ値は等しく比較され、同じ配列の要素へのポインタはそれらの要素の配列インデックスと同じように比較され、同じメンバアクセスを持つ非静的データメンバへのポインタはそれらのメンバの宣言順に比較されます。
多くの実装では、ランダムな起源のポインタに対して厳密な全順序も提供しています。例えば、連続した仮想アドレス空間内のアドレスとして実装されている場合です。そうでない実装 (例えば、ポインタのすべてのビットがメモリアドレスの一部ではなく、比較のために無視する必要がある場合、または追加の計算が必要な場合、あるいはポインタと整数が1対1の関係でない場合) では、その保証を持つポインタのためのstd::lessの特殊化を提供します。これにより、std::setやstd::mapのような標準の連想コンテナのキーとして、すべてのランダムな起源のポインタを使用することが可能になります。
[編集] voidへのポインタ
任意の型のオブジェクトへのポインタは、(おそらくcv修飾された)voidへのポインタに暗黙的に変換できます。ポインタの値は変更されません。static_castまたは明示的なキャストを必要とする逆変換は、元のポインタ値を生成します。
int n = 1; int* p1 = &n; void* pv = p1; int* p2 = static_cast<int*>(pv); std::cout << *p2 << '\n'; // prints 1
元のポインタがポリモーフィック型オブジェクト内の基底クラスのサブオブジェクトを指している場合、dynamic_castを使用して、最も派生した型の完全なオブジェクトを指すvoid*を取得できます。
voidへのポインタは、charへのポインタと同じサイズ、表現、アライメントを持ちます。
voidへのポインタは、Cインターフェースでよく見られる未知の型のオブジェクトを渡すために使用されます。std::mallocはvoid*を返し、std::qsortは2つのconst void*引数を受け入れるユーザー提供のコールバックを期待します。pthread_createは、void*を受け入れて返すユーザー提供のコールバックを期待します。すべての場合において、使用前にポインタを正しい型にキャストするのは呼び出し元の責任です。
[編集] 関数へのポインタ
関数へのポインタは、非メンバ関数または静的メンバ関数のアドレスで初期化できます。関数からポインタへの暗黙の変換により、アドレス演算子はオプションです。
void f(int); void (*p1)(int) = &f; void (*p2)(int) = f; // same as &f
関数や関数への参照とは異なり、関数へのポインタはオブジェクトであるため、配列に格納したり、コピーしたり、代入したりすることができます。
void (a[10])(int); // Error: array of functions void (&a[10])(int); // Error: array of references void (*a[10])(int); // OK: array of pointers to functions
注: 関数へのポインタを含む宣言は、型エイリアスを使用することで簡略化できることが多いです。
using F = void(int); // named type alias to simplify declarations F a[10]; // Error: array of functions F& a[10]; // Error: array of references F* a[10]; // OK: array of pointers to functions
関数へのポインタは関数呼び出し演算子の左オペランドとして使用でき、これにより指し示された関数が呼び出されます。
int f(int n) { std::cout << n << '\n'; return n * n; } int main() { int (*p)(int) = f; int x = p(7); }
関数ポインタを逆参照すると、指し示された関数を識別する左辺値が生成されます。
int f(); int (*p)() = f; // pointer p is pointing to f int (&r)() = *p; // the lvalue that identifies f is bound to a reference r(); // function f invoked through lvalue reference (*p)(); // function f invoked through the function lvalue p(); // function f invoked directly through the pointer
関数へのポインタは、オーバーロードセット (関数、関数テンプレート特殊化、関数テンプレートを含む場合があります) から初期化できます。ただし、ポインタの型に一致するオーバーロードが1つだけの場合です (詳細についてはオーバーロード関数のアドレスを参照してください)。
template<typename T> T f(T n) { return n; } double f(double n) { return n; } int main() { int (*p)(int) = f; // instantiates and selects f<int> }
関数へのポインタに対して等値比較演算子が定義されています (同じ関数を指していれば等しいと比較されます)。
[編集] メンバへのポインタ
[編集] データメンバへのポインタ
クラス C のメンバである非静的メンバオブジェクト m へのポインタは、厳密に式 &C::m で初期化できます。&(C::m) や C のメンバ関数内の &m のような式は、メンバへのポインタを形成しません。
そのようなポインタは、メンバへのポインタアクセス演算子 operator.* および operator->* の右オペランドとして使用できます。
アクセス可能な曖昧性のない非仮想基底クラスのデータメンバへのポインタは、派生クラスの同じデータメンバへのポインタに暗黙的に変換できます。
struct Base { int m; }; struct Derived : Base {}; int main() { int Base::* bp = &Base::m; int Derived::* dp = bp; Derived d; d.m = 1; std::cout << d.*dp << ' ' << d.*bp << '\n'; // prints 1 1 }
逆方向の変換、すなわち派生クラスのデータメンバへのポインタから曖昧性のない非仮想基底クラスのデータメンバへのポインタへの変換は、基底クラスにそのメンバがない場合でも (ただし、ポインタがアクセスに使用されるときに最も派生したクラスにはある場合)、static_castと明示的なキャストで許可されます。
メンバへのポインタの指し示す型は、それ自体がメンバへのポインタである場合があります。メンバへのポインタは多段階になり、各レベルで異なるcv修飾を持つことができます。ポインタとメンバへのポインタの混合多段階の組み合わせも許可されます。
struct A { int m; // const pointer to non-const member int A::* const p; }; int main() { // non-const pointer to data member which is a const pointer to non-const member int A::* const A::* p1 = &A::p; const A a = {1, &A::m}; std::cout << a.*(a.*p1) << '\n'; // prints 1 // regular non-const pointer to a const pointer-to-member int A::* const* p2 = &a.p; std::cout << a.**p2 << '\n'; // prints 1 }
[編集] メンバ関数へのポインタ
クラス C のメンバである非静的メンバ関数 f へのポインタは、厳密に式 &C::f で初期化できます。&(C::f) や C のメンバ関数内の &f のような式は、メンバ関数へのポインタを形成しません。
そのようなポインタは、メンバへのポインタアクセス演算子 operator.* および operator->* の右オペランドとして使用できます。結果の式は、関数呼び出し演算子の左オペランドとしてのみ使用できます。
struct C { void f(int n) { std::cout << n << '\n'; } }; int main() { void (C::* p)(int) = &C::f; // pointer to member function f of class C C c; (c.*p)(1); // prints 1 C* cp = &c; (cp->*p)(2); // prints 2 }
基底クラスのメンバ関数へのポインタは、派生クラスの同じメンバ関数へのポインタに暗黙的に変換できます。
struct Base { void f(int n) { std::cout << n << '\n'; } }; struct Derived : Base {}; int main() { void (Base::* bp)(int) = &Base::f; void (Derived::* dp)(int) = bp; Derived d; (d.*dp)(1); (d.*bp)(2); }
逆方向の変換、すなわち派生クラスのメンバ関数へのポインタから曖昧性のない非仮想基底クラスのメンバ関数へのポインタへの変換は、基底クラスにそのメンバ関数がない場合でも (ただし、ポインタがアクセスに使用されるときに最も派生したクラスにはある場合)、static_castと明示的なキャストで許可されます。
struct Base {}; struct Derived : Base { void f(int n) { std::cout << n << '\n'; } }; int main() { void (Derived::* dp)(int) = &Derived::f; void (Base::* bp)(int) = static_cast<void (Base::*)(int)>(dp); Derived d; (d.*bp)(1); // okay: prints 1 Base b; (b.*bp)(2); // undefined behavior }
メンバ関数へのポインタは、多くの場合std::mem_fnまたはstd::bindを適用した後、コールバックまたは関数オブジェクトとして使用できます。
#include <algorithm> #include <cstddef> #include <functional> #include <iostream> #include <string> int main() { std::vector<std::string> v = {"a", "ab", "abc"}; std::vector<std::size_t> l; transform(v.begin(), v.end(), std::back_inserter(l), std::mem_fn(&std::string::size)); for (std::size_t n : l) std::cout << n << ' '; std::cout << '\n'; }
出力
1 2 3
[編集] ヌルポインタ
すべての型のポインタには、その型のヌルポインタ値として知られる特殊な値があります。値がヌルのポインタはオブジェクトや関数を指しません (ヌルポインタを逆参照する動作は未定義です)。また、同じ型の他のすべてのヌル値のポインタと比較して等しいとされます。
ヌルポインタ定数は、ポインタをヌルで初期化したり、既存のポインタにヌル値を代入したりするために使用できます。それは以下の値のいずれかです。
- 値がゼロの整数リテラル。
|
(C++11以降) |
マクロNULLも使用できます。これは実装定義のヌルポインタ定数に展開されます。
ヌルポインタは、オブジェクトの不在を示すため (例: std::function::target()) や、その他のエラー条件インジケータとして (例: dynamic_cast) 使用できます。一般的に、ポインタ引数を受け取る関数は、値がヌルであるかどうかをほぼ常にチェックし、そのケースを異なる方法で処理する必要があります (例えば、delete式はヌルポインタが渡されたときに何も行いません)。
[編集] 無効なポインタ
ポインタ値 p が評価 e のコンテキストで有効であるのは、以下の条件のいずれかが満たされる場合です。
- p はヌルポインタ値である。
- p は関数へのポインタである。
- p はオブジェクト o の終端または終端を超えたポインタであり、e は o のストレージ領域の期間内にある。
ポインタ値 p が評価 e で使用され、p が e のコンテキストで有効でない場合、
int* f() { int obj; int* local_ptr = new (&obj) int; *local_ptr = 1; // OK, the evaluation “*local_ptr” is // in the storage duration of “obj” return local_ptr; } int* ptr = f(); // the storage duration of “obj” is expired, // therefore “ptr” is an invalid pointer in the following contexts int* copy = ptr; // implementation-defined behavior *ptr = 2; // undefined behavior: indirection of an invalid pointer delete ptr; // undefined behavior: deallocating storage from an invalid pointer
[編集] Const性
- ポインタ宣言でcvが
*の前に現れる場合、それは宣言指定子シーケンスの一部であり、指し示されるオブジェクトに適用されます。 - ポインタ宣言でcvが
*の後に現れる場合、それは宣言子の一部であり、宣言されるポインタに適用されます。
| 構文 | 意味 |
|---|---|
| const T* | 定数オブジェクトへのポインタ |
| T const* | 定数オブジェクトへのポインタ |
| T* const | オブジェクトへの定数ポインタ |
| const T* const | 定数オブジェクトへの定数ポインタ |
| T const* const | 定数オブジェクトへの定数ポインタ |
// pc is a non-const pointer to const int // cpc is a const pointer to const int // ppc is a non-const pointer to non-const pointer to const int const int ci = 10, *pc = &ci, *const cpc = pc, **ppc; // p is a non-const pointer to non-const int // cp is a const pointer to non-const int int i, *p, *const cp = &i; i = ci; // okay: value of const int copied into non-const int *cp = ci; // okay: non-const int (pointed-to by const pointer) can be changed pc++; // okay: non-const pointer (to const int) can be changed pc = cpc; // okay: non-const pointer (to const int) can be changed pc = p; // okay: non-const pointer (to const int) can be changed ppc = &pc; // okay: address of pointer to const int is pointer to pointer to const int ci = 1; // error: const int cannot be changed ci++; // error: const int cannot be changed *pc = 2; // error: pointed-to const int cannot be changed cp = &ci; // error: const pointer (to non-const int) cannot be changed cpc++; // error: const pointer (to const int) cannot be changed p = pc; // error: pointer to non-const int cannot point to const int ppc = &p; // error: pointer to pointer to const int cannot point to // pointer to non-const int
一般に、ある多段階ポインタから別の多段階ポインタへの暗黙の変換は、修飾変換に記載されている規則に従います。
[編集] 複合ポインタ型
比較演算子のオペランド、または条件演算子の第2オペランドおよび第3オペランドのいずれかがポインタまたはメンバへのポインタである場合、複合ポインタ型はこれらのオペランドの共通の型として決定されます。
それぞれ型T1とT2を持つ2つのオペランドp1とp2が与えられたとき、p1とp2が複合ポインタ型を持つことができるのは、以下の条件のいずれかが満たされる場合のみです。
|
(C++14まで) | ||
|
(C++14以降) |
p1とp2の複合ポインタ型Cは、次のように決定されます。
|
(C++11まで) |
|
(C++11以降) |
- そうでなければ、以下のすべての条件が満たされる場合、
-
T1またはT2が「cv1 voidへのポインタ」である。 - もう一方の型が「cv2
Tへのポインタ」である。ここでTはオブジェクト型またはvoidである。
-
-
Cは「cv12 voidへのポインタ」である。ここでcv12はcv1とcv2の結合である。
|
(C++17以降) |
- そうでなければ、以下のすべての条件が満たされる場合、
-
T1は「C1へのポインタ」である。 -
T2は「C2へのポインタ」である。 C1とC2のいずれかがもう一方に参照関連である。
-
-
Cは、C1がC2に参照関連している場合、T1とT2の修飾結合型、またはC2がC1に参照関連している場合、T2とT1の修飾結合型。
|
(C++17以降) |
- そうでなければ、以下のすべての条件が満たされる場合、
-
T1は「非関数型M1のC1のメンバへのポインタ」である。 -
T2は「非関数型M2のC2のメンバへのポインタ」である。 -
M1とM2はトップレベルのcv修飾を除いて同じである。 C1とC2のいずれかがもう一方に参照関連である。
-
-
Cは、C1がC2に参照関連している場合、T2とT1の修飾結合型、またはC2がC1に参照関連している場合、T1とT2の修飾結合型。
- そうでなければ、
T1とT2が類似の型である場合、CはT1とT2の修飾結合型です。 - そうでなければ、p1とp2は複合ポインタ型を持たず、そのような型
Cの決定を必要とするプログラムは不正な形式となります。
using p = void*; using q = const int*; // The determination of the composite pointer type of “p” and “q” // falls into the [“pointer to cv1 void” and “pointer to cv2 T”] case: // cv1 = empty, cv2 = const, cv12 = const // substitute “cv12 = const” into “pointer to cv12 void”: // the composite pointer type is “const void*” using pi = int**; using pci = const int**; // The determination of the composite pointer type of “pi” and “pci” // falls into the [pointers to similar types “C1” and “C2”] case: // C1 = int*, C2 = const int* // they are reference-related types (in both direction) because they are similar // the composite pointer type is the qualification-combined type // of “p1” and “pc1” (or that of “pci” and “pi”): “const void* const *”
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 73 | C++98 | オブジェクトへのポインタは、 配列の終端を超えたポインタとは等しく比較されない。 |
ヌルでも関数ポインタでもないポインタの場合、 それらが表すアドレスを比較する。 |
| CWG 903 | C++98 | 0に評価される任意の整数定数式が ヌルポインタ定数であった。 |
値0の整数リテラルに 限定された。 |
| CWG 1438 | C++98 | 無効なポインタ値をどのように使用しても 動作は未定義であった。 |
逆参照と 解放関数への引渡し以外の動作は 実装定義である。 |
| CWG 1512 (N3624) |
C++98 | 複合ポインタ型のルールが不完全であり、その結果 int**とconst int**の比較が許可されなかった。 |
完全になった。 |
| CWG 2206 | C++98 | voidへのポインタと 関数へのポインタは複合ポインタ型を持っていた。 |
それらはそのような型を持たない。 |
| CWG 2381 | C++17 | 複合ポインタ型を決定する際に 関数ポインタ変換が許可されなかった。 |
許可 |
| CWG 2822 | C++98 | ストレージ領域の期間の終わりに到達すると ポインタ値が無効になる可能性があった。 |
ポインタの有効性は 評価コンテキストに基づいている。 |
| CWG 2933 | C++98 | 関数へのポインタは常に無効であった。 | それらは常に有効である。 |
[編集] 関連項目
| Cドキュメントのポインタ宣言
|