名前空間
変種
操作

ポインタ宣言

提供: cppreference.com
< cpp‎ | language
 
 
C++言語
一般的なトピック
フロー制御
条件付き実行文
繰り返し文 (ループ)
ジャンプ文
関数
関数宣言
ラムダ関数宣言
inline 指定子
例外指定 (C++20未満)
noexcept 指定子 (C++11)
例外
名前空間
指定子
decltype (C++11)
auto (C++11)
alignas (C++11)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点
文字 - 文字列 - nullptr (C++11)
ユーザ定義 (C++11)
ユーティリティ
属性 (C++11)
typedef 宣言
型エイリアス宣言 (C++11)
キャスト
暗黙の変換 - 明示的な変換
static_cast - dynamic_cast
const_cast - reinterpret_cast
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

ポインタ型またはメンバへのポインタ型の変数を宣言します。

目次

[編集] 構文

ポインタ宣言は宣言子が以下の形式を持つ任意の単純宣言です。

* attr(オプション) cv(オプション) declarator (1)
nested-name-specifier * attr(オプション) cv(オプション) declarator (2)
1) ポインタ宣言子。 宣言 S* D;decl-specifier-seq S によって決定される型へのポインタとして D を宣言します。
2) メンバへのポインタ宣言子。 宣言 S C::* D;decl-specifier-seq S によって決定される型の C の非静的メンバへのポインタとして D を宣言します。
declarator - 参照宣言子以外の任意の宣言子 (参照へのポインタはありません)。 別のポインタ宣言子でも構いません (ポインタへのポインタは許されます)。
attr(C++11) - オプショナルな属性のリスト。
cv - 宣言されているポインタに適用する const/volatile 修飾 (指す先の型にではありません。 その修飾は decl-specifier-seq の一部です)。
nested-name-specifier - 名前とスコープ解決演算子 :: の並び。

参照へのポインタおよびビットフィールドへのポインタはありません。 一般的には、ただ単に「ポインタ」と言ったとき、 (非静的) メンバへのポインタは含みません。

[編集] ポインタ

ポインタ型のすべての値は以下のいずれかです。

  • オブジェクトまたは関数へのポインタ (この場合、ポインタはそのオブジェクトまたは関数を指すと言います)。
  • オブジェクトの最後の次へのポインタ
  • その型のヌルポインタ値
  • 無効なポインタ値

オブジェクトを指すポインタはそのオブジェクトが占めるメモリの最初のバイトのアドレスを表します。 オブジェクトの最後の次を指すポインタはそのオブジェクトが占める記憶域の最後より後のメモリの最初のバイトのアドレスを表します

同じアドレスを表す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; // たとえ assert に引っかからなくても未定義動作です。


無効なポインタ値を通した間接参照および無効なポインタ値を解放関数に渡すことは未定義動作です。 無効なポインタ値のそれ以外のあらゆる使用は処理系定義動作です。

[編集] オブジェクトへのポインタ

オブジェクトへのポインタはオブジェクト型の任意の式に適用されたアドレス取得演算子の戻り値で初期化できます。

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*) への被演算子として使用することができ、指す先のオブジェクトを表す左辺値式を返します。

int n;
int* p = &n;     // n へのポインタ。
int& r = *p;     // 参照は n を表す左辺値式に束縛されます。
r = 7;           // n に int の 7 を格納します。
std::cout << *p; // 左辺値から右辺値への暗黙の変換により 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] (int 8個の配列3個の配列) へのポインタ。

ポインタに対する派生から基底への暗黙の変換のため、基底へのポインタは派生クラスのアドレスで初期化できます。

struct Base {};
struct Derived : Base {};
 
Derived d;
Base* p = &d;

Derived多相の場合、そのようなポインタは仮想関数呼び出しを行うために使用することができます。

配列の要素へのポインタに対して加算、減算インクリメントおよびデクリメント演算子が定義されます。 そのようなポインタは LegacyRandomAccessIterator の要件を満たし、 C++ ライブラリのアルゴリズムを生の配列で使えるようにします。

いくつかの状況ではオブジェクトへのポインタに対して比較演算子が定義されます。 同じアドレスを表す2つのポインタは等しく、2つのヌルポインタ値は等しく、同じ配列の要素へのポインタはそれらの要素のインデックスと同じに比較され、同じメンバアクセスを持つ非静的データメンバへのポインタはそれらのメンバの宣言の順序で比較されます。

多くの処理系は任意の起源のポインタの狭義全順序も提供します (例えば、連続的な仮想アドレス空間内のアドレスとして実装される場合)。 そうでない処理系 (例えばポインタのビットのすべてがメモリアドレスの部分ではなく比較の際には無視する必要があるとか、追加の計算が必要であるとか、ポインタと整数が1対1の関係でないなど) は、そのような保証を持つポインタに対する std::less の特殊化を提供します。 これは std::setstd::map などの標準の連想コンテナで任意の起源のポインタすべてをキーとして使用することを可能とします。

[編集] void へのポインタ

あらゆる型のオブジェクトへのポインタは void (cv 修飾しても構いません) へのポインタに暗黙に変換できます。 ポインタ値は変わりません。 逆変換 (static_cast または explicit cast が必要です) は元のポインタ値を生成します。

int n = 1;
int* p1 = &n;
void* pv = p1;
int* p2 = static_cast<int*>(pv);
std::cout << *p2 << '\n'; // 1 を表示します。

元のポインタが何らかの多相型のオブジェクト内の基底クラス部分オブジェクトを指している場合、その最も派生した型の完全なオブジェクトを指す void* を取得するために dynamic_cast を使用することができます。

void へのポインタは不明な型のオブジェクトを渡すために使用されます。 これは C のインタフェースでは一般的です。 std::mallocvoid* を返し、 std::qsort は2つの const void* 引数を受け取るユーザ提供コールバックを期待します。 pthread_createvoid* を受け取り void* を返すユーザ提供コールバックを期待します。 すべての場合において、ポインタを使用する前に正しい型にキャストするのは呼び出し元の責任です。


[編集] 関数へのポインタ

関数へのポインタは非メンバ関数または静的メンバ関数のアドレスで初期化できます。 関数からポインタへの暗黙の変換のため、アドレス取得演算子はオプショナルです。

void f(int);
void (*p1)(int) = &f;
void (*p2)(int) = f; // &f と同じです。

関数または関数への参照と異なり、関数へのポインタはオブジェクトであり、そのため配列に格納したり、コピーしたり、代入したりできます。

関数へのポインタは関数呼び出し演算子の左側の被演算子として使用することができます。 これは指す先の関数を呼びます。

int f(int n)
{
    std::cout << n << '\n';
    return n * n;
}
 
int main()
{
    int (*p)(int) = f;
    int x = p(7); // f を呼びます。
}

関数ポインタの逆参照は指す先の関数を表す左辺値を生成します。

int f();
int (*p)() = f;  // ポインタ p は f を指しています。
int (&r)() = *p; // f を表す左辺値が参照に束縛されます。
r();             // 左辺値参照を通して関数 f が呼ばれます。
(*p)();          // 関数の左辺値を通して関数 f が呼ばれます。
p();             // ポインタを直接通して関数 f が呼ばれます。

関数へのポインタは、そのポインタの型にマッチするオーバーロードがひとつだけであれば、関数、関数テンプレートの特殊化、および関数テンプレートを含む、オーバーロード集合から初期化することができます (さらなる詳細についてはオーバーロードされた関数のアドレスを参照してください)。

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 C { int m; };
 
int main()
{
    int C::* p = &C::m;          // クラス C のデータメンバ m へのポインタ。
    C c = {7};
    std::cout << c.*p << '\n';   // 7 を表示します。
    C* cp = &c;
    cp->m = 10;
    std::cout << cp->*p << '\n'; // 10 を表示します。
}

アクセス可能な曖昧でない非仮想基底クラスのデータメンバへのポインタは、派生クラスの同じデータメンバへのポインタに暗黙に変換できます。

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 および explicit cast で変換できます (たとえ基底クラスがそのメンバを持たない (けれどもそのポインタがアクセスに使用されたときの最も派生したクラスは持つ) 場合でも)。

struct Base {};
struct Derived : Base { int m; };
 
int main()
{
    int Derived::* dp = &Derived::m;
    int Base::* bp = static_cast<int Base::*>(dp);
 
    Derived d;
    d.m = 7;
    std::cout << d.*bp << '\n'; // OK、 7 を表示します。
 
    Base b;
    std::cout << b.*bp << '\n'; // 未定義動作。
}

メンバへのポインタの指す先の型がメンバへのポインタでも構いません。 メンバへのポインタは多段にでき、段ごとに異なる 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 なメンバへの const なポインタへの非 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 および明示的なキャストで変換できます (たとえ基底クラスがそのメンバを持たない (けれどもそのポインタがアクセスに使用されたときの最も派生したクラスは持つ) 場合でも)。

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); // OK、 1 を表示します。
 
    Base b;
    (b.*bp)(2); // 未定義動作。
}

メンバ関数へのポインタは (しばしば std::mem_fnstd::bind を適用した後に) コールバックとしてまたは関数オブジェクトとして使用されることがあります。

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
 
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 << ' ';
}

出力:

1 2 3

[編集] ヌルポインタ

すべての型のポインタには、その型のヌルポインタ値という特殊な値があります。 値がヌルのポインタはオブジェクトや関数を指さず (ヌルポインタの逆参照は未定義動作です)、値がヌルの同じ型のすべてのポインタと等しいと比較されます。

ポインタをヌルに初期化するまたは既存のポインタにヌル値を代入するためには、ヌルポインタリテラル nullptr、ヌルポインタ定数 NULL、または整数値 0 からの暗黙の変換を使用することができます。

ゼロ初期化および値初期化もポインタをヌル値に初期化します。

ヌルポインタはオブジェクトの不在を表したり (例えば function::target())、その他のエラー状況のインジケータとして (例えば dynamic_cast) 使用することができます。 一般的には、ポインタ引数を受け取る関数は、ほとんど必ず、値がヌルかどうかを調べてその場合に異なる処理をする必要があります (例えば delete 式はヌルポインタが渡されたときは何もしません)。

[編集] 定数性

  • ポインタ宣言において cv* の前に現れた場合、それは decl-specifier-seq の一部であり、指す先のオブジェクトに適用されます。
  • ポインタ宣言において cv* の後に現れた場合、それは declarator の一部であり、宣言されているポインタに適用されます。
構文 意味
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;    // OK、const な int の値が非 const な int にコピーされます。
*cp = ci;  // OK、非 const な int (const なポインタによって指されている) は変更できます。
pc++;      // OK、非 const なポインタ (const な int を指している) は変更できます。
pc = cpc;  // OK、非 const なポインタ (const な int を指している) は変更できます。
pc = p;    // OK、非 const なポインタ (const な int を指している) は変更できます。
ppc = &pc; // OK、const な int へのポインタのアドレスは const な int へのポインタへのポインタです。
 
ci = 1;    // エラー、const な int は変更できません。
ci++;      // エラー、const な int は変更できません。
*pc = 2;   // エラー、const な int (非 const なポインタによって指されている) は変更できません。
cp = &ci;  // エラー、const なポインタ (非 const な int を指している) は変更できません。
cpc++;     // エラー、const なポインタ (const な int を指している) は変更できません。
p = pc;    // エラー、非 const な int へのポインタは const な int を指すことはできません。
ppc = &p;  // エラー、const な int へのポインタへのポインタは
           // 非 const な int へのポインタを指すことはできません。

一般的に、ある多段ポインタから別の多段ポインタへの暗黙の変換は、修飾子変換およびポインタ比較演算子で説明されているルールに従います。

[編集] 関連項目

ポインタ宣言C言語リファレンス