名前空間
変種
操作

非静的データメンバ

提供: 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
メモリ確保
クラス
クラス固有の関数特性
特別なメンバ関数
テンプレート
その他
 
 

非静的データメンバはクラスのメンバ仕様における宣言です。

class S
{
    int n;                // 非静的データメンバ。
    int& r;               // 参照型の非静的データメンバ。
    int a[2] = {1, 2};    // デフォルトメンバ初期化子付きの非静的データメンバ (C++11)。
    std::string s, *ps;   // 2個の非静的データメンバ。
    struct NestedS {
        std::string s;
    } d5;                 // ネストした型の非静的データメンバ。
    char bit : 2;         // 2ビットのビットフィールド。
};

任意の単純宣言が使用できます。 ただし、

  • extern および register 記憶域クラス指定子は使用できません。
  • thread_local 記憶域クラス指定子は使用できません (静的データメンバに対しては使用できます)。
  • 不完全型抽象クラス型、およびそれらの配列は使用できません。 特に、クラス CC 型の非静的データメンバを持つことはできません (C& (C への参照) 型または C* (C へのポインタ) 型の非静的データメンバを持つことはできます)。
  • ユーザ宣言されたコンストラクタが少なくともひとつ存在する場合、非静的データメンバはクラスの名前と同じ名前を持つことはできません。
  • auto 指定子は非静的データメンバの宣言では使用できません (クラス定義内で初期化される静的データメンバに対しては使用できます)。

さらに、ビットフィールドの宣言が使用できます。

目次

[編集] レイアウト

何らかのクラス C のオブジェクトが作成されるとき、非参照型の非静的データメンバはそれぞれ C のオブジェクト表現のどこかの部分に確保されます。 参照メンバが何らかの記憶域を占めるかどうかは処理系定義ですが、記憶域期間はそのメンバが所属するオブジェクトのものと同じです。

共用体クラス型の場合、同じメンバアクセスかつ非ゼロのサイズ (C++20以上)を持つメンバは常に、後に宣言されたメンバがクラスオブジェクト内でより高位のアドレスを持つように確保されます。 異なるアクセス制御を持つメンバは未規定の順序で確保されます (コンパイラはそれらを一緒にグループ化するかもしれません)。 アライメント要件によりメンバ間やクラスの最後のメンバの後にパディングが必要となる場合があります。

[編集] 標準レイアウト

すべての非静的データメンバが同じアクセス制御を持ち、その他の一定の条件を満たすクラスは、標準レイアウト型と言います (要件の一覧については StandardLayoutType を参照してください)。

ひとつ以上の先頭のメンバの並び (宣言順) について、それらのメンバがレイアウト互換な型である場合かつそれらがすべて [[no_unique_address]] 属性付きで宣言されたかすべてその属性なしで宣言された場合 (C++20以上)かつそれらがビットフィールドの場合は同じ幅を持つ場合 (C++14以上)、2つの標準レイアウト非共用体クラス型は非静的データメンバおよびビットフィールド (C++14以上)共通先頭列を持つことがあります。

struct A { int a; char b; };
struct B { const int b1; volatile char b2; }; 
// A と B の共通先頭列は A.a, A.b と B.b1, B.b2 です。
struct C { int c; unsigned : 0; char b; };
// A と C の共通先頭列は A.a と C.c です。
struct D { int d; char b : 4; };
// A と D の共通先頭列は A.a と D.d です。
struct E { unsigned int e; char b; };
// A と E の共通先頭列は空です。

2つの標準レイアウト非共用体クラス型が、同じ型である (cv 修飾は無視します) (C++14以上)、レイアウト互換な列挙 (すなわち同じ型をベースとする列挙) である、またはそれらの共通先頭列がすべての非静的データメンバおよびビットフィールド (C++14以上)から構成される場合、それらはレイアウト互換であると言います (上の例では、 AB はレイアウト互換です)。

2つの標準レイアウト共用体が、同じ数の非静的データメンバを持ち、対応する非静的データメンバ (順不同) がレイアウト互換な型である場合、それらはレイアウト互換であると言います。

標準レイアウト型は以下の特別な性質を持ちます。

  • 標準レイアウト共用体が2つ (以上) の標準レイアウトクラスをメンバとして保持し、それらのクラスがデータメンバの共通先頭列を持つ場合、その共用体のどのメンバがアクティブかにかかわらず、その共通先頭列のいかなるメンバを調べることも well-defined です。
(C++14未満)
  • 非共用体クラス型 T1 のアクティブメンバを持つ標準レイアウト共用体において、 mT1T2 の共通先頭列の一部であれば、非共用体クラス型 T2 の別の共用体メンバの非静的データメンバ m を読むことが許されます (ただし非 volatile な glvalue を通して volatile なメンバを読むことは未定義です)。
(C++14以上)
  • 標準レイアウトクラス型のオブジェクトへのポインタは、その最初の非静的非ビットフィールドデータメンバ (非静的データメンバを持つ場合) またはそうでなければその基底クラス部分オブジェクトのいずれか (もしあれば) へのポインタに、またはその逆に、 reinterpret_cast することができます。 別の言い方をすると、標準レイアウト型の最初のデータメンバの前にはパディングが許されません。 そのようなキャストの結果には厳密なエイリアシングのルールが未だ適用されることに注意してください。
  • マクロ offsetof は標準レイアウトクラスの先頭から任意のメンバへのオフセットを決定するために使用することができます。

[編集] メンバの初期化

非静的データメンバは2つの方法のいずれかで初期化できます。

1) コンストラクタのメンバ初期化子リストで。
struct S
{
    int n;
    std::string s;
    S() : n(7) // n は直接初期化され、 s はデフォルト初期化されます。
    { }
};
2) デフォルトメンバ初期化子を通して。 これはメンバの宣言に含まれる波括弧または等号の初期化子であり、そのメンバがコンストラクタのメンバ初期化子リストに含まれていない場合に使用されます。
struct S
{
    int n = 7;
    std::string s{'a', 'b', 'c'};
    S() // デフォルトメンバ初期化子により、 n はコピー初期化され、 s はリスト初期化されます。
    { }
};

メンバがデフォルトメンバ初期化子を持ち、コンストラクタのメンバ初期化子リストにも現れる場合、そのコンストラクタに対してはデフォルトメンバ初期化子は無視されます。

#include <iostream>
 
int x = 0;
struct S
{
    int n = ++x;
    S() { }                 // デフォルトメンバ初期化子を使用します。
    S(int arg) : n(arg) { } // メンバ初期化子リストを使用します。
};
 
int main()
{
    std::cout << x << '\n'; // 0 を表示します。
    S s1;
    std::cout << x << '\n'; // 1 を表示します (デフォルト初期化子が実行されました)。
    S s2(7);
    std::cout << x << '\n'; // 1 を表示します (デフォルト初期化子は実行されませんでした)。
}

出力:

0
1
1

デフォルトメンバ初期化子はビットフィールドメンバに対しては使用できません。

(C++20未満)

配列型のメンバのサイズをメンバ初期化子から推定することはできません。

struct X {
   int a[] = {1,2,3}; // エラー。
   int b[3] = {1,2,3}; // OK。
};

デフォルトメンバ初期化子は囲っているクラスに対するデフォルト化されたデフォルトコンストラクタの暗黙の定義またはそのコンストラクタの例外指定の原因となってはなりません。 :

struct node {
    node* p = new node; // エラー、暗黙のまたはデフォルト化された node::node() の使用。
};
(C++11以上)

参照メンバをデフォルトメンバ初期化子で一時オブジェクトに束縛することはできません (注: メンバ初期化子リストに対しても同じルールが存在します)。

struct A
{
    A() = default;          // OK。
    A(int v) : v(v) { }     // OK。
    const int& v = 42;      // OK。
};
A a1;    // エラー、一時オブジェクトの参照への ill-formed な束縛
A a2(1); // OK (コンストラクタ内で v が初期化されているためデフォルトメンバ初期化子は無視されます)
         // ですが、 a2.v はダングリング参照です。

参照メンバは、同じ初期化子を使用する集成体初期化を実行する部分式を持つことになる場合、デフォルトメンバ初期化子では初期化できません。

struct A;
extern A a;
struct A
{
    const A& a1{ A{a, a} }; // OK。
    const A& a2{ A{} };     // エラー。
};
A a{a, a};                  // OK。
(C++14以上)

[編集] 使用方法

非静的データメンバまたは非静的メンバ関数の名前は、以下の3つの状況でのみ現れることができます。

1) そのメンバを持つクラスまたはそのメンバを持つクラスの派生クラスの、クラスメンバアクセス式の一部として。 this が使用できる文脈 (メンバ関数の本体の内側、メンバ初期化子リスト内、クラス内デフォルトメンバ初期化子内) で非静的メンバの名前が使用されるときに現れる暗黙の this-> のメンバアクセス式を含みます。
struct S
{
    int m;
    int n;
    int x = m;            // OK、デフォルトメンバ初期化子で暗黙の this-> が使用できます (C++11)。
    S(int i) : m(i), n(m) // OK、メンバ初期化子リストで暗黙の this-> が使用できます。
    {
        this->f();        // 明示的なメンバアクセス式。
        f();              // メンバ関数本体内で暗黙の this-> が使用できます。
    }
    void f();
};
2) 非静的メンバへのポインタを形成するため。
struct S
{
   int m;
   void f();
};
int S::*p = &S::m;       // OK、メンバへのポインタを作成するための m の使用。
void (S::*fp)() = &S::f; // OK、メンバへのポインタを作成するための f の使用。
3) 未評価被演算子内で使用されるとき (データメンバに対してのみです。 メンバ関数には適用されません)。
struct S
{
   int m;
   static const std::size_t sz = sizeof m; // OK、 m は未評価被演算子です。
};
std::size_t j = sizeof(S::m + 42); // OK、たとえここでは m のための「this」オブジェクトがなくても。
(C++03以上)

[編集] 欠陥報告

以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。

DR 適用先 発行時の動作 正しい動作
CWG 613 C++03 unevaluated uses of non-static data members not allowed such uses are allowed
CWG 1696 C++14 reference members could be initialized to temporaries (whose lifetime would end at the end of ctor) such init is ill-formed
CWG 1397 C++11 class was regarded as complete in the default member initializers default member init cannot trigger definition of default ctor
CWG 1719 C++14 differently cv-qualified types weren't layout-compatible cv-quals ignored, spec improved
CWG 2254 C++14 pointer to standard-layout class with no data members can be reinterpret_cast to its first base class can be reinterpret_cast to any of its base classes

[編集] 関連項目