Pointer declaration
ポインタまたはメンバへのポインタ型の変数を宣言します。
目次 |
構文
ポインタ宣言は、 宣言子 が以下の形式を持つ任意の単純宣言です。
*
attr
(オプション)
cv
(オプション)
declarator
|
(1) | ||||||||
nested-name-specifier
*
attr
(オプション)
cv
(オプション)
declarator
|
(2) | ||||||||
C
の非静的メンバへのポインタとして宣言し、その型は宣言指定子シーケンス
S
によって決定される。
| nested-name-specifier | - |
名前とスコープ解決演算子
のシーケンス
::
|
| attr | - | (C++11以降) 属性 のリスト |
| cv | - | 宣言されているポインタに適用されるconst/volatile修飾(指し示される型の修飾は宣言指定子シーケンスの一部であり、これには含まれない) |
| declarator | - | 任意の 宣言子 |
ポインタから 参照 へのポインタは存在せず、 ビットフィールド へのポインタも存在しません。 通常、特に明記されていない場合の「ポインタ」という言及には、(非静的)メンバへのポインタは含まれません。
ポインタ
ポインタ型のすべての値は、以下のいずれかです:
- オブジェクトまたは関数への ポインタ (この場合、ポインタはそのオブジェクトまたは関数を 指す と言います)、または
- オブジェクトの終端を超える ポインタ 、または
- その型の ヌルポインタ値 、または
- 無効なポインタ値 。
オブジェクトを指すポインタは、 そのオブジェクトがメモリ上で占有する最初のバイトのアドレス を表します。オブジェクトの終端を過ぎたポインタは、 そのオブジェクトが占有するストレージの終端後の最初のバイトのアドレス を表します。
同じアドレスを表す2つのポインタであっても、異なる値を持つ可能性があることに注意してください。
struct C { int x, y; } c; int* px = &c.x; // pxの値は「c.xへのポインタ」 int* pxe= px + 1; // pxeの値は「c.xの終端を過ぎたポインタ」 int* py = &c.y; // pyの値は「c.yへのポインタ」 assert(pxe == py); // == は2つのポインタが同じアドレスを表すかテストする // アサーションが発生する場合としない場合がある *pxe = 1; // アサーションが発生しなくても未定義動作
無効なポインタ値を通じた間接参照および無効なポインタ値を解放関数に渡すことは未定義動作を引き起こします。無効なポインタ値のその他の使用は処理系定義の動作となります。一部の実装では、無効なポインタ値のコピーがシステム生成のランタイムフォルトを引き起こすと定義する場合があります。
オブジェクトへのポインタ
オブジェクトへのポインタは、オブジェクト型の任意の式(他のポインタ型を含む)に アドレス演算子 を適用した戻り値で初期化できます:
int n; int* np = &n; // intへのポインタ int* const* npp = &np; // 非const intへのconstポインタへの非constポインタ int a[2]; int (*ap)[2] = &a; // int配列へのポインタ struct S { int n; }; S s = {1}; int* sp = &s.n; // sのメンバであるintへのポインタ
ポインタは組み込みの間接参照演算子(単項 operator * )のオペランドとして現れ、これが指し示すオブジェクトを特定する lvalue式 を返します:
int n; int* p = &n; // nへのポインタ int& r = *p; // 参照はnを識別するlvalue式に束縛される r = 7; // nにint値7を格納 std::cout << *p; // lvalueからrvalueへの暗黙変換によりnから値を読み取る
クラスオブジェクトへのポインタは、メンバアクセス演算子
operator->
および
operator->*
の左辺オペランドとしても使用できます。
配列からポインタへの 暗黙変換 により、配列の最初の要素へのポインタは配列型の式で初期化できます:
int a[2]; int* p1 = a; // 配列aの最初の要素a[0](int型)へのポインタ int b[6][3][8]; int (*p2)[3][8] = b; // 配列bの最初の要素b[0]へのポインタ、 // これは8個のintの配列3個からなる配列
ポインタに対する derived-to-base 暗黙変換のため、基底クラスへのポインタは派生クラスのアドレスで初期化できます:
struct Base {}; struct Derived : Base {}; Derived d; Base* p = &d;
Derived
が
ポリモーフィック
である場合、そのようなポインタは
仮想関数呼び出し
を行うために使用されることがあります。
特定の 加算、減算 、 インクリメント、デクリメント 演算子は配列要素へのポインタに対して定義されています:このようなポインタは LegacyRandomAccessIterator 要件を満たし、C++ライブラリの アルゴリズム が生配列を扱うことを可能にします。
比較演算子 は、いくつかの状況においてオブジェクトへのポインタに対して定義されています:同じアドレスを表す2つのポインタは等しいと比較され、2つのヌルポインタ値は等しいと比較され、同じ配列の要素へのポインタはそれらの要素の配列インデックスと同じように比較され、同じ メンバーアクセス を持つ非静的データメンバーへのポインタは、それらのメンバーの宣言順に比較されます。
多くの実装では、ランダムな起源のポインタの 厳密な全順序付け も提供されています(例えば、連続した仮想アドレス空間内のアドレスとして実装されている場合)。これを提供しない実装(例えば、ポインタの全ビットがメモリアドレスの一部ではなく比較時に無視する必要がある場合、追加の計算が必要な場合、あるいはポインタと整数が1対1の関係にない場合など)では、その保証を持つポインタ用の std::less の特殊化を提供しています。これにより、ランダムな起源のすべてのポインタを std::set や std::map のような標準の連想コンテナのキーとして使用することが可能になります。
voidへのポインタ void
任意の型へのオブジェクトポインタは、
暗黙的に変換
可能です(場合によっては
cv修飾
された)
void
ポインタへ。ポインタ値は変更されません。逆変換には
static_cast
または
明示的キャスト
が必要であり、元のポインタ値を返します:
int n = 1; int* p1 = &n; void* pv = p1; int* p2 = static_cast<int*>(pv); std::cout << *p2 << '\n'; // 1を出力
元のポインタが何らかのポリモーフィック型のオブジェクト内の基底クラスのサブオブジェクトを指している場合、
dynamic_cast
を使用して、最も派生した型の完全なオブジェクトを指す
void
*
を取得することができます。
void へのポインタは、 char へのポインタと同じサイズ、表現、アラインメントを持ちます。
voidへのポインタは、未知の型のオブジェクトを渡すために使用され、これはCインターフェースで一般的です:
void
は
std::malloc
が
void
*
を返し、
std::qsort
は2つの
const
void
*
引数を受け入れるユーザー提供のコールバックを期待します。
pthread_create
は
void
*
を受け入れ、返すユーザー提供のコールバックを期待します。すべての場合において、使用前にポインタを正しい型にキャストするのは呼び出し側の責任です。
関数へのポインタ
関数へのポインタは、非メンバ関数または静的メンバ関数のアドレスで初期化できます。 関数からポインタへの 暗黙変換により、アドレス取得演算子は省略可能です:
void f(int); void (*p1)(int) = &f; void (*p2)(int) = f; // &f と同じ
関数や関数への参照とは異なり、関数へのポインタはオブジェクトであるため、配列への格納、コピー、代入などが可能です。
void (a[10])(int); // エラー: 関数の配列 void (&a[10])(int); // エラー: 参照の配列 void (*a[10])(int); // OK: 関数へのポインタの配列
注: 関数ポインタを含む宣言は、多くの場合型エイリアスを使用して簡略化できます:
using F = void(int); // 宣言を簡略化するための名前付き型エイリアス F a[10]; // エラー: 関数の配列 F& a[10]; // エラー: 参照の配列 F* a[10]; // OK: 関数へのポインタの配列
関数へのポインタは 関数呼び出し演算子 の左側オペランドとして使用でき、これによって指し示される関数を呼び出します:
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; // ポインタpはfを指している int (&r)() = *p; // fを識別する左辺値が参照に束縛されている r(); // 左辺値参照を通じて関数fが呼び出される (*p)(); // 関数左辺値を通じて関数fが呼び出される p(); // ポインタを直接介して関数fが呼び出される
関数へのポインタは、オーバーロードの集合から初期化することができます。この集合には、関数、関数テンプレートの特殊化、および関数テンプレートが含まれる場合がありますが、ポインタの型に一致するオーバーロードが1つだけ存在する場合に限ります(詳細は オーバーロードされた関数のアドレス を参照してください):
template<typename T> T f(T n) { return n; } double f(double n) { return n; } int main() { int (*p)(int) = f; // 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'; // 1 1 を出力 }
逆方向の変換、派生クラスのデータメンバへのポインタから明確な非仮想基底クラスのデータメンバへのポインタへの変換は、
static_cast
および
明示的キャスト
によって許可されます(基底クラスがそのメンバを持っていない場合でも、最も派生したクラスが持っており、ポインタがアクセスに使用されるときに):
メンバへのポインタが指す型は、それ自体がメンバへのポインタである可能性があります:メンバへのポインタは多段階にでき、各レベルで異なるcv修飾を持つことができます。ポインタとメンバへのポインタの混合多段階組み合わせも許可されます:
struct A { int m; // 非constメンバへのconstポインタ int A::* const p; }; int main() { // 非constメンバへのconstポインタであるデータメンバへの非constポインタ int A::* const A::* p1 = &A::p; const A a = {1, &A::m}; std::cout << a.*(a.*p1) << '\n'; // 1を出力 // constポインタ-to-memberへの通常の非constポインタ int A::* const* p2 = &a.p; std::cout << a.**p2 << '\n'; // 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; // クラスCのメンバ関数fへのポインタ C c; (c.*p)(1); // 1を出力 C* cp = &c; (cp->*p)(2); // 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
および
explicit 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); // 正常: 1を出力 Base b; (b.*bp)(2); // 未定義動作 }
メンバ関数へのポインタは、コールバックまたは関数オブジェクトとして使用されることがあり、多くの場合 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
ヌルポインタ
すべての型のポインタは、その型の nullポインタ値 として知られる特別な値を持ちます。値がnullであるポインタは、オブジェクトや関数を指しません(nullポインタをデリファレンスする動作は未定義です)、そして値が同様に null である同じ型のすべてのポインタと等しいと比較されます。
null pointer constant は、ポインタをnullに初期化するため、または既存のポインタにnull値を代入するために使用できます。これは以下のいずれかの値です:
- 値がゼロの整数リテラル。
|
(C++11以降) |
マクロ NULL も使用可能であり、これは実装定義のヌルポインタ定数に展開されます。
Zero-initialization および value-initialization もポインタをそのnull値に初期化します。
ヌルポインタはオブジェクトが存在しないことを示すために使用できます(例: std::function::target() )、または他のエラー状態の指標としても使用されます(例: dynamic_cast )。一般的に、ポインタ引数を受け取る関数は、値がヌルかどうかをチェックし、そのケースを別途処理する必要がほとんどです(例えば、 delete expression はヌルポインタが渡された場合には何も行いません)。
無効なポインタ
ポインタ値 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: 評価「*local_ptr」は // 「obj」のストレージ期間内にある return local_ptr; } int* ptr = f(); // 「obj」のストレージ期間が終了したため、 // 以降のコンテキストにおいて「ptr」は無効なポインタとなる int* copy = ptr; // 実装定義の動作 *ptr = 2; // 未定義動作: 無効なポインタの間接参照 delete ptr; // 未定義動作: 無効なポインタからのストレージ解放
Const性
-
cv
がポインタ宣言内で
*の前に現れる場合、それは宣言指定子シーケンスの一部であり、指し示されるオブジェクトに適用されます。 -
cv
がポインタ宣言内で
*の後に現れる場合、それは 宣言子 の一部であり、宣言されているポインタ自体に適用されます。
| 構文 | 意味 |
|---|---|
| const T * | 定数オブジェクトへのポインタ |
| T const * | 定数オブジェクトへのポインタ |
| T * const | オブジェクトへの定数ポインタ |
| const T * const | 定数オブジェクトへの定数ポインタ |
| T const * const | 定数オブジェクトへの定数ポインタ |
// pc は const int への非constポインタ // cpc は const int へのconstポインタ // ppc は const int への非constポインタへの非constポインタ const int ci = 10, *pc = &ci, *const cpc = pc, **ppc; // p は非const int への非constポインタ // cp は非const int へのconstポインタ int i, *p, *const cp = &i; i = ci; // 正常: const int の値が非const int にコピーされる *cp = ci; // 正常: constポインタが指す非const int は変更可能 pc++; // 正常: const int への非constポインタは変更可能 pc = cpc; // 正常: const int への非constポインタは変更可能 pc = p; // 正常: const int への非constポインタは変更可能 ppc = &pc; // 正常: const int へのポインタのアドレスは const int へのポインタへのポインタ ci = 1; // エラー: const int は変更不可 ci++; // エラー: const int は変更不可 *pc = 2; // エラー: 指し示されたconst int は変更不可 cp = &ci; // エラー: 非const int へのconstポインタは変更不可 cpc++; // エラー: const int へのconstポインタは変更不可 p = pc; // エラー: 非const int へのポインタはconst int を指せない ppc = &p; // エラー: const int へのポインタへのポインタは // 非const int へのポインタを指せない
一般的に、ある多段階ポインタから別の多段階ポインタへの暗黙的変換は、 資格変換 で説明されている規則に従います。
複合ポインタ型
比較演算子のオペランド、または 比較演算子 の第2オペランドと第3オペランドのいずれかがポインタまたはポインタ-to-memberである場合、これらのオペランドの共通型として複合ポインタ型が決定されます。
2つのオペランド
p1
と
p2
がそれぞれ
T1
と
T2
の型を持つ場合、
p1
と
p2
が複合ポインタ型を持つのは、以下の条件のいずれかが満たされる場合に限ります:
|
(C++14まで) | ||
|
(C++14以降) |
合成ポインタ型
C
は、
p1
と
p2
の以下のように決定されます:
|
(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のいずれか一方が他方に対して reference-related です。
-
-
Cは-
C1がC2に対してreference-relatedである場合、T1とT2の qualification-combined type 、または -
C2がC1に対してreference-relatedである場合、T2とT1のqualification-combined typeです。
-
|
(C++17以降) |
- それ以外の場合、以下のすべての条件が満たされるならば:
-
-
T1は「非関数型M1のC1メンバへのポインタ」です。 -
T2は「非関数型M2のC2メンバへのポインタ」です。 -
M1とM2はトップレベルのcv修飾を除いて同じ型です。 -
C1とC2の一方が他方に対してreference-relatedです。
-
-
Cは以下のいずれかです:-
C1がC2に対してreference-relatedの場合、T2とT1の修飾結合型(qualification-combined type)、または -
C2がC1に対してreference-relatedの場合、T1とT2の修飾結合型(qualification-combined type)。
-
-
それ以外の場合、
T1とT2が 類似型 である場合、CはT1とT2の修飾子合成型となる。 -
それ以外の場合、
p1
と
p2
は複合ポインタ型を持たず、
Cを決定する必要があるプログラムはそのような型に対して不適格となる。
using p = void*; using q = const int*; // 「p」と「q」の複合ポインタ型の決定は // [「cv1 voidへのポインタ」と「cv2 Tへのポインタ」]の場合に該当: // cv1 = 空, cv2 = const, cv12 = const // 「cv12 = const」を「cv12 voidへのポインタ」に代入: // 複合ポインタ型は「const void*」 using pi = int**; using pci = const int**; // 「pi」と「pci」の複合ポインタ型の決定は // [類似型「C1」と「C2」へのポインタ]の場合に該当: // C1 = int*, C2 = const int* // これらは類似型であるため参照関連型(双方向) // 複合ポインタ型は「p1」と「pc1」 // (または「pci」と「pi」)の修飾結合型:「const int**」
不具合報告
以下の動作変更の欠陥報告書は、以前に公開された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 documentation
for
Pointer declaration
|
|
C documentation
の
Pointer declaration
|