私はこの用語PODタイプに数回遭遇しました。
どういう意味ですか?
私はこの用語PODタイプに数回遭遇しました。
どういう意味ですか?
回答:
PODは、Plain Old Dataの略です。struct
つまり、class
コンストラクター、デストラクター、および仮想メンバー関数のないクラス(キーワードまたはキーワードで定義されているかどうか)です。ウィキペディアのPODに関する記事では、もう少し詳しく説明し、次のように定義しています。
C ++のプレーンオールドデータ構造は、メンバーとしてPODSのみを含み、ユーザー定義のデストラクター、ユーザー定義のコピー代入演算子、およびポインターからメンバーへの型の非静的メンバーを持たない集約クラスです。
詳細については、C ++ 98/03のこの回答をご覧ください。C ++ 11はPODを取り巻く規則を変更し、それらを大幅に緩和したため、ここでフォローアップの回答が必要となりました。
PODはタイプ(クラスを含む)であり、C ++コンパイラは構造内で「マジック」が発生しないことを保証します。たとえば、vtableへの隠しポインタ、他のタイプにキャストされたときにアドレスに適用されるオフセット(少なくとも、ターゲットのPODも)、コンストラクタ、またはデストラクタ。大まかに言えば、その中にある唯一のものが組み込み型とそれらの組み合わせである場合、型はPODです。結果は、Cタイプのように「振る舞う」ものです。
int
、char
、wchar_t
、bool
、float
、double
などあり、PODをしているlong/short
とsigned/unsigned
、それらのバージョン。enums
PODですconst
またはvolatile
PODは、PODです。class
、struct
又はunion
鞘のPODは、すべての非静的データメンバーであることが提供されるpublic
、そしてそれは、ベースクラスなしコンストラクタ、デストラクタ、または仮想メソッドを持っていません。静的メンバーは、このルールの下で何かがPODであることを止めません。このルールはC ++ 11で変更され、特定のプライベートメンバーが許可されています。すべてのプライベートメンバーを持つクラスをPODクラスにすることはできますか?3.9(10):「算術型(3.9.1)、列挙型、ポインター型、メンバー型へのポインター(3.9.2)、およびこれらの型のcv修飾バージョン(3.9.3)は、集合的に呼び出し元のスカラー型です。スカラータイプ、POD構造体タイプ、PODユニオンタイプ(9節)、そのようなタイプの配列、およびこれらのタイプのcv修飾バージョン(3.9.3)は、まとめてPODタイプと呼ばれます。
9(4):「POD構造体は、非POD構造体型、非PODユニオン型(またはそのような型の配列)または参照型の非静的データメンバーを持たない集計クラスであり、ユーザーコピー演算子を定義し、ユーザー定義のデストラクタはありません。同様に、PODユニオンは、非POD構造、非PODユニオン(またはそのようなタイプの配列)、または参照の非静的データメンバーを持たない集約ユニオンです。また、ユーザー定義のコピー演算子とユーザー定義のデストラクタはありません。
8.5.1(1):「集約は配列またはクラス(9節)であり、ユーザー宣言コンストラクター(12.1)、プライベートまたは保護された非静的データメンバー(11節)、基本クラス(10節)はありません。仮想機能はありません(10.3)。」
要するに、それはすべてのデータ型(例えば、内蔵されたint
、char
、float
、long
、unsigned char
、double
、など)とPODデータをすべて集約。はい、それは再帰的な定義です。;)
より明確にするために、PODは「構造体」と呼ばれるものです。データを格納するだけのユニットまたはユニットのグループです。
私が理解しているように、POD(PlainOldData)は単なる生データです-それは必要ありません:
何かがPODかどうかを確認するにはどうすればよいですか?まあ、それを呼び出すための構造体がありますstd::is_pod
:
namespace std {
// Could use is_standard_layout && is_trivial instead of the builtin.
template<typename _Tp>
struct is_pod
: public integral_constant<bool, __is_pod(_Tp)>
{ };
}
(ヘッダーtype_traitsから)
参照:
POD(プレーンオールドデータ)オブジェクトは、これらのデータ型の1つ(基本型、ポインター、共用体、構造体、配列、またはクラス)を持ち、コンストラクターはありません。逆に、非PODオブジェクトは、コンストラクターが存在するオブジェクトです。PODオブジェクトは、そのタイプに適したサイズのストレージを取得するとライフタイムを開始し、オブジェクトのストレージが再利用または割り当て解除されたときに終了します。
また、PlainOldData型には、次のものを含めることはできません。
PlainOldDataの緩い定義には、コンストラクターを持つオブジェクトが含まれます。ただし、仮想的なものはすべて除外されます。PlainOldDataタイプの重要な問題は、それらが非多態性であることです。継承はPODタイプで行うことができますが、実装形態継承(コードの再利用)に対してのみ行う必要があり、ポリモーフィズム/サブタイピングでは行わないでください。
一般的な(厳密には正しくありませんが)定義は、PlainOldData型はVeeTableを持たないものです。
PODと非PODをまったく区別する必要があるのはなぜですか?
C ++はCの拡張として生まれました。現在のC ++はもはやCの厳密なスーパーセットではありませんが、人々はまだ2つの間の高いレベルの互換性を期待しています。
大まかに言えば、POD型はCと互換性があり、おそらく同じくらい重要なことに、特定のABI最適化と互換性がある型です。
Cと互換性を持たせるには、2つの制約を満たす必要があります。
特定のC ++機能はこれと互換性がありません。
仮想メソッドを使用するには、コンパイラーが仮想メソッドテーブルへのポインターを1つ以上挿入する必要があります。これはCには存在しないものです。
ユーザー定義のコピーコンストラクター、移動コンストラクター、コピーの割り当て、およびデストラクタは、パラメーターの受け渡しと戻りに影響を与えます。多くのC ABIはレジスタに小さなパラメータを渡して返しますが、ユーザー定義のコンストラクタ/割り当て/デストラクタに渡される参照は、メモリロケーションでのみ機能します。
したがって、「C互換」であると期待できる型とできない型を定義する必要があります。C ++ 03はこの点でいくらか厳格でした。ユーザー定義のコンストラクターは組み込みコンストラクターを無効にし、それらを追加しようとすると、ユーザー定義になり、タイプが非ポッドになります。C ++ 11は、ユーザーが組み込みのコンストラクターを再導入できるようにすることで、物事をかなり開きました。
static_assert
C ++ 11からC ++ 17までのすべての非PODケースとPOD効果の例
std::is_pod
C ++ 11で追加されたので、とりあえずその標準以降について考えてみましょう。
std::is_pod
https://stackoverflow.com/a/48435532/895245で言及されているように、C ++ 20から削除されます。交換のサポートが到着したら、これを更新しましょう。
標準が進化するにつれて、PODの制限はますます緩和されるようになりました。ifdefを使用して、例のすべての緩和をカバーすることを目指しています。
libstdc ++は、https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.ccでテストを行っていますが、少なすぎる。メンテナ:この投稿を読んだら、これをマージしてください。/software/199708/is-there-a-compliance-test-for-c-compilersで言及されているすべてのC ++テストスイートプロジェクトをチェックするのは面倒です。
#include <type_traits>
#include <array>
#include <vector>
int main() {
#if __cplusplus >= 201103L
// # Not POD
//
// Non-POD examples. Let's just walk all non-recursive non-POD branches of cppreference.
{
// Non-trivial implies non-POD.
// https://en.cppreference.com/w/cpp/named_req/TrivialType
{
// Has one or more default constructors, all of which are either
// trivial or deleted, and at least one of which is not deleted.
{
// Not trivial because we removed the default constructor
// by using our own custom non-default constructor.
{
struct C {
C(int) {}
};
static_assert(std::is_trivially_copyable<C>(), "");
static_assert(!std::is_trivial<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
// No, this is not a default trivial constructor either:
// https://en.cppreference.com/w/cpp/language/default_constructor
//
// The constructor is not user-provided (i.e., is implicitly-defined or
// defaulted on its first declaration)
{
struct C {
C() {}
};
static_assert(std::is_trivially_copyable<C>(), "");
static_assert(!std::is_trivial<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
}
// Not trivial because not trivially copyable.
{
struct C {
C(C&) {}
};
static_assert(!std::is_trivially_copyable<C>(), "");
static_assert(!std::is_trivial<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
}
// Non-standard layout implies non-POD.
// https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
{
// Non static members with different access control.
{
// i is public and j is private.
{
struct C {
public:
int i;
private:
int j;
};
static_assert(!std::is_standard_layout<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
// These have the same access control.
{
struct C {
private:
int i;
int j;
};
static_assert(std::is_standard_layout<C>(), "");
static_assert(std::is_pod<C>(), "");
struct D {
public:
int i;
int j;
};
static_assert(std::is_standard_layout<D>(), "");
static_assert(std::is_pod<D>(), "");
}
}
// Virtual function.
{
struct C {
virtual void f() = 0;
};
static_assert(!std::is_standard_layout<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
// Non-static member that is reference.
{
struct C {
int &i;
};
static_assert(!std::is_standard_layout<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
// Neither:
//
// - has no base classes with non-static data members, or
// - has no non-static data members in the most derived class
// and at most one base class with non-static data members
{
// Non POD because has two base classes with non-static data members.
{
struct Base1 {
int i;
};
struct Base2 {
int j;
};
struct C : Base1, Base2 {};
static_assert(!std::is_standard_layout<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
// POD: has just one base class with non-static member.
{
struct Base1 {
int i;
};
struct C : Base1 {};
static_assert(std::is_standard_layout<C>(), "");
static_assert(std::is_pod<C>(), "");
}
// Just one base class with non-static member: Base1, Base2 has none.
{
struct Base1 {
int i;
};
struct Base2 {};
struct C : Base1, Base2 {};
static_assert(std::is_standard_layout<C>(), "");
static_assert(std::is_pod<C>(), "");
}
}
// Base classes of the same type as the first non-static data member.
// TODO failing on GCC 8.1 -std=c++11, 14 and 17.
{
struct C {};
struct D : C {
C c;
};
//static_assert(!std::is_standard_layout<C>(), "");
//static_assert(!std::is_pod<C>(), "");
};
// C++14 standard layout new rules, yay!
{
// Has two (possibly indirect) base class subobjects of the same type.
// Here C has two base classes which are indirectly "Base".
//
// TODO failing on GCC 8.1 -std=c++11, 14 and 17.
// even though the example was copy pasted from cppreference.
{
struct Q {};
struct S : Q { };
struct T : Q { };
struct U : S, T { }; // not a standard-layout class: two base class subobjects of type Q
//static_assert(!std::is_standard_layout<U>(), "");
//static_assert(!std::is_pod<U>(), "");
}
// Has all non-static data members and bit-fields declared in the same class
// (either all in the derived or all in some base).
{
struct Base { int i; };
struct Middle : Base {};
struct C : Middle { int j; };
static_assert(!std::is_standard_layout<C>(), "");
static_assert(!std::is_pod<C>(), "");
}
// None of the base class subobjects has the same type as
// for non-union types, as the first non-static data member
//
// TODO: similar to the C++11 for which we could not make a proper example,
// but with recursivity added.
// TODO come up with an example that is POD in C++14 but not in C++11.
}
}
}
// # POD
//
// POD examples. Everything that does not fall neatly in the non-POD examples.
{
// Can't get more POD than this.
{
struct C {};
static_assert(std::is_pod<C>(), "");
static_assert(std::is_pod<int>(), "");
}
// Array of POD is POD.
{
struct C {};
static_assert(std::is_pod<C>(), "");
static_assert(std::is_pod<C[]>(), "");
}
// Private member: became POD in C++11
// /programming/4762788/can-a-class-with-all-private-members-be-a-pod-class/4762944#4762944
{
struct C {
private:
int i;
};
#if __cplusplus >= 201103L
static_assert(std::is_pod<C>(), "");
#else
static_assert(!std::is_pod<C>(), "");
#endif
}
// Most standard library containers are not POD because they are not trivial,
// which can be seen directly from their interface definition in the standard.
// /programming/27165436/pod-implications-for-a-struct-which-holds-an-standard-library-container
{
static_assert(!std::is_pod<std::vector<int>>(), "");
static_assert(!std::is_trivially_copyable<std::vector<int>>(), "");
// Some might be though:
// /programming/3674247/is-stdarrayt-s-guaranteed-to-be-pod-if-t-is-pod
static_assert(std::is_pod<std::array<int, 1>>(), "");
}
}
// # POD effects
//
// Now let's verify what effects does PODness have.
//
// Note that this is not easy to do automatically, since many of the
// failures are undefined behaviour.
//
// A good initial list can be found at:
// /programming/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special/4178176#4178176
{
struct Pod {
uint32_t i;
uint64_t j;
};
static_assert(std::is_pod<Pod>(), "");
struct NotPod {
NotPod(uint32_t i, uint64_t j) : i(i), j(j) {}
uint32_t i;
uint64_t j;
};
static_assert(!std::is_pod<NotPod>(), "");
// __attribute__((packed)) only works for POD, and is ignored for non-POD, and emits a warning
// /programming/35152877/ignoring-packed-attribute-because-of-unpacked-non-pod-field/52986680#52986680
{
struct C {
int i;
};
struct D : C {
int j;
};
struct E {
D d;
} /*__attribute__((packed))*/;
static_assert(std::is_pod<C>(), "");
static_assert(!std::is_pod<D>(), "");
static_assert(!std::is_pod<E>(), "");
}
}
#endif
}
テスト済み:
for std in 11 14 17; do echo $std; g++-8 -Wall -Werror -Wextra -pedantic -std=c++$std pod.cpp; done
Ubuntu 18.04、GCC 8.2.0。
C ++では、Plain Old Dataは、int、charなどが使用される唯一のタイプであることを意味するだけではありません。プレーンオールドデータとは、実際には、メモリ内のある場所から別の場所にstruct memcpyを取得でき、期待どおりに動作する(つまり、爆発しない)ことを意味します。これは、クラス、またはクラスに含まれているクラスが、ポインターまたは参照であるメンバーとして、あるいは仮想関数を持つクラスとして持っている場合に機能しなくなります。基本的に、ポインタがどこかに含まれる必要がある場合、それは単純な古いデータではありません。