名前空間
変種
操作

ポインタ宣言

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

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

目次

[編集] 構文

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

* attr (optional) cv (optional) declarator (1)
nested-name-specifier * attr (optional) cv (optional) declarator (2)
1) ポインタ宣言子: 宣言 S* D; は、宣言指定子シーケンス S で決定される型へのポインタとして D を宣言します。
2) メンバへのポインタ宣言子: 宣言 S C::* D; は、宣言指定子シーケンス 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::setstd::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::mallocvoid*を返し、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 C { int m; };
 
int main()
{
    int C::* p = &C::m;          // pointer to data member m of class C
    C c = {7};
    std::cout << c.*p << '\n';   // prints 7
    C* cp = &c;
    cp->m = 10;
    std::cout << cp->*p << '\n'; // prints 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'; // prints 1 1
}

逆方向の変換、すなわち派生クラスのデータメンバへのポインタから曖昧性のない非仮想基底クラスのデータメンバへのポインタへの変換は、基底クラスにそのメンバがない場合でも (ただし、ポインタがアクセスに使用されるときに最も派生したクラスにはある場合)、static_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'; // okay: prints 7
 
    Base b;
    std::cout << b.*bp << '\n'; // undefined behavior
}

メンバへのポインタの指し示す型は、それ自体がメンバへのポインタである場合があります。メンバへのポインタは多段階になり、各レベルで異なる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 の終端または終端を超えたポインタであり、eo のストレージ領域の期間内にある。

ポインタ値 p が評価 e で使用され、pe のコンテキストで有効でない場合、

  • もし 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オペランドのいずれかがポインタまたはメンバへのポインタである場合、複合ポインタ型はこれらのオペランドの共通の型として決定されます。

それぞれ型T1T2を持つ2つのオペランドp1p2が与えられたとき、p1p2が複合ポインタ型を持つことができるのは、以下の条件のいずれかが満たされる場合のみです。

  • p1p2の両方がポインタである。
  • p1p2のいずれかがポインタであり、もう一方のオペランドがヌルポインタ定数である。
  • p1p2の両方がヌルポインタ定数であり、T1T2の少なくとも一方が非整数型である。
(C++11以降)
(C++14まで)
  • T1T2の少なくとも一方がポインタ型、メンバへのポインタ型、またはstd::nullptr_tである。
(C++14以降)

p1p2複合ポインタ型Cは、次のように決定されます。

  • p1ヌルポインタ定数の場合、CT2です。
  • そうでなければ、p2がヌルポインタ定数である場合、CT1です。
(C++11まで)
  • p1p2の両方がヌルポインタ定数である場合、Cstd::nullptr_tです。
  • そうでなければ、p1がヌルポインタ定数である場合、CT2です。
  • そうでなければ、p2がヌルポインタ定数である場合、CT1です。
(C++11以降)
  • そうでなければ、以下のすべての条件が満たされる場合、
  • T1またはT2が「cv1 voidへのポインタ」である。
  • もう一方の型が「cv2 Tへのポインタ」である。ここでTオブジェクト型またはvoidである。
Cは「cv12 voidへのポインタ」である。ここでcv12cv1cv2の結合である。
  • そうでなければ、以下のすべての条件が満たされる場合、
  • T1またはT2が「関数型F1へのポインタ」である。
  • もう一方の型が「noexcept関数型F2へのポインタ」である。
  • F1F2はnoexceptを除いて同じである。
Cは「F1へのポインタ」である。
(C++17以降)
  • そうでなければ、以下のすべての条件が満たされる場合、
  • T1は「C1へのポインタ」である。
  • T2は「C2へのポインタ」である。
  • C1C2のいずれかがもう一方に参照関連である。
Cは、
  • C1C2に参照関連している場合、T1T2修飾結合型、または
  • C2C1に参照関連している場合、T2T1の修飾結合型。
  • そうでなければ、以下のすべての条件が満たされる場合、
  • T1またはT2が「関数型F1C1のメンバへのポインタ」である。
  • もう一方の型が「noexcept関数型F2C2のメンバへのポインタ」である。
  • C1C2のいずれかがもう一方に参照関連である。
  • F1F2はnoexceptを除いて同じである。
Cは、
  • C1C2に参照関連している場合、「型F1C2のメンバへのポインタ」、または
  • C2C1に参照関連している場合、「型F1C1のメンバへのポインタ」。
(C++17以降)
  • そうでなければ、以下のすべての条件が満たされる場合、
  • T1は「非関数型M1C1のメンバへのポインタ」である。
  • T2は「非関数型M2C2のメンバへのポインタ」である。
  • M1M2はトップレベルのcv修飾を除いて同じである。
  • C1C2のいずれかがもう一方に参照関連である。
Cは、
  • C1C2に参照関連している場合、T2T1の修飾結合型、または
  • C2C1に参照関連している場合、T1T2の修飾結合型。
  • そうでなければ、T1T2類似の型である場合、CT1T2の修飾結合型です。
  • そうでなければ、p1p2は複合ポインタ型を持たず、そのような型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ドキュメントポインタ宣言
English 日本語 中文(简体) 中文(繁體)