コンテンツにスキップ

POD

POD (Plain Old Data) とは C と ABI 互換性が保証されるデータ構造のことです。

データ構造が POD であるかは std::is_pod で判定することができます。 std::is_pod を使用するには <type_traits> のインクルードが必要です。 データ構造を POD にしたい場合には static_assert で保証するとよいです。

#include <type_traits>
struct FundamentalTypes {
    int16_t i;
    double d;
};
static_assert(std::is_pod<FundamentalTypes>::value, "Should be POD.");

基本型

基本型は POD です。

enum Direction {
    kLeft,
    kRight,
    kBoth
};

static_assert(std::is_pod<char>::value, "Should be POD.");
static_assert(std::is_pod<int32_t>::value, "Should be POD.");
static_assert(std::is_pod<double>::value, "Should be POD.");
static_assert(std::is_pod<Direction>::value, "Should be POD.");

配列

POD の配列は POD です。

static_assert(std::is_pod<int[2]>::value, "Should be POD.");

POD の std::array も POD ですが、 POD の std::vector は POD ではありません。

static_assert(std::is_pod<std::array<int, 2>>::value, "Should be POD.");
static_assert(std::is_pod<std::vector<int>>::value, "Should be POD.");  // failed

参照型

参照型は POD ではありません。

static_assert(std::is_pod<int&>::value, "Should be POD.");  // failed

ポインタ型

あらゆるポインタは POD です。 POD ではない型に対するポインタも POD です。

static_assert(std::is_pod<int*>::value, "Should be POD.");

// std::vector<int> は POD ではないが std::vector<int>* は POD
static_assert(std::is_pod<std::vector<int>*>::value, "Should be POD.");

構造体

構造体の条件は複雑なため、本書では簡単な例だけを紹介します。

POD の要件

トリビアルかつスタンダードレイアウトである場合に POD となります。 詳細は以下を参照してください。

POD になる構造体の例

以下の条件をすべて満たす構造体は POD です。

  • 継承していない
  • メンバ関数を持たない (暗黙的に定義される特別なメンバ関数は明示しない)
  • すべてのデータメンバは POD
  • データメンバに対するアクセス指定子が1種類のみ (暗黙的な public 指定も含む)
// データメンバを持たない
struct Empty {};
static_assert(std::is_pod<Empty>::value, "Should be POD.");

// すべてのデータメンバが基本型
struct FundamentalTypes {
    int16_t i;
    double d;
};
static_assert(std::is_pod<FundamentalTypes>::value, "Should be POD.");

POD の構造体は入れ子にすることができます。

// POD の構造体 FundamentalTypes をデータメンバにもつ
struct FundamentalTypesAsChild {
    char c;
    FundamentalTypes f;
};
static_assert(std::is_pod<FundamentalTypesAsChild>::value, "Should be POD.");

// POD の構造体 FundamentalTypesAsChild をデータメンバにもつ
struct FundamentalTypesAsGrandchild {
    char c;
    FundamentalTypesAsChild f;
};
static_assert(std::is_pod<FundamentalTypesAsGrandchild>::value,
              "Should be POD.");

POD にならない構造体の例

暗黙的に定義される特別なメンバ関数をユーザ定義

ユーザ定義のデフォルトコンストラクタをもつ構造体は POD ではありません。

struct UserDefinedDefaultConstructor {
    UserDefinedDefaultConstructor() {}
};
static_assert(std::is_pod<UserDefinedDefaultConstructor>::value,
              "Should be POD.");  // failed

default 指定であれば POD になります。

struct DefaultConstructorAsExplicitDefault {
    DefaultConstructorAsExplicitDefault() = default;
};

static_assert(std::is_pod<DefaultConstructorAsExplicitDefault>::value,
              "Should be POD.");

デフォルトコンストラクタ以外の 暗黙的に定義される特別なメンバ関数についても同様です。

仮想関数

仮想関数をもつ構造体は POD ではありません。

struct VirtualFunction {
    virtual void Hoge() {}
};
static_assert(std::is_pod<VirtualFunction>::value, "Should be POD.");  // failed

非 POD のデータメンバ

POD ではない型の非 static データメンバを持つ構造体は POD ではありません。

struct NonPodMemberVariable {
    std::vector<int> v;  // std::vector<int> は POD ではない
};
static_assert(std::is_pod<NonPodMemberVariable>::value, "Should be POD.");  // failed

データメンバに対するアクセス指定子が2種類以上

暗黙的なものを含めて、 static ではないデータメンバに対するアクセス指定子が2種類以上ある構造体は POD ではありません。

struct MultipleAccessSpecifierTypes {
    int public_variable;

 private:
    int private_variable;
};
static_assert(std::is_pod<MultipleAccessSpecifierTypes>::value, "Should be POD.");  // failed

クラス

C++ における構造体とクラスの違いはデフォルトのアクセス指定子だけなので、 構造体と同じ条件でクラスも POD になります。

class FundamentalTypes {
 public:
    int16_t i;
    double d;
};
static_assert(std::is_pod<FundamentalTypes>::value, "Should be POD.");