c++ - 入門 - memcpy pod
C++のPODタイプとは何ですか? (6)
私はこの言葉を数回POD型に遭遇しました。 どういう意味ですか?
非常に非公式に:
PODは、C ++コンパイラが構造内で「マジック」が起こらないことを保証するタイプ(クラスを含む)です。例えば、vtableへの隠れポインタ、他の型にキャストされたときにアドレスに適用されるオフセット少なくともターゲットのPODでも)、コンストラクタ、またはデストラクタ。 おおまかに言えば、タイプはPODであり、その中の唯一のものは組み込みのタイプとその組み合わせです。 その結果、C型のように動作します。
あまり非公式に:
-
int
、char
、wchar_t
、bool
、float
、double
はPODであり、long/short
とsigned/unsigned
型です。 - ポインタ(関数へのポインタとメンバへのポインタを含む)はPODであり、
-
enums
はPODです -
const
またはvolatile
PODはPODです。 - PODの
class
、struct
またはunion
struct
は、すべての非静的データ・メンバーがpublic
であり、基本クラスを持たず、コンストラクター、デストラクタ、または仮想メソッドを持たない場合、PODです。 静的メンバーは、このルールの下で何かPODであることを止めません。 このルールはC ++ 11で変更されています。一部のプライベートメンバーは許可されています: すべてのプライベートメンバーを持つクラスはPODクラスですか? - Wikipediaは、PODがメンバへのポインタ型のメンバを持つことができないと言っても間違いです。 あるいは、C ++ 98の言い回しには間違いありませんが、TC1はポインタへのポインタがPODであることを明示しました。
正式に(C ++ 03標準):
3.9(10): 「算術型(3.9.1)、列挙型、ポインタ型、およびメンバ型へのポインタ(3.9.2)およびこれらの型のCV修飾バージョン(3.9.3)は、まとめて呼び出し側スカラ型です。 POD-struct型、POD-union型(9節)、そのような型の配列とこれらの型のcv修飾版(3.9.3)はまとめてPOD型と呼ばれます "
9(4): 「POD構造体は、非POD構造体、非POD結合体(またはそのような型の配列)または参照型の非静的データメンバーを持たず、ユーザー定義のデータメンバを持たない集約クラスです。同様に、POD-unionは、non-POD-struct、非POD-union(またはそのような型の配列)または参照型の非静的データメンバーを持たない集合体であり、ユーザー定義のコピー演算子もユーザー定義のデストラクタもありません。
8.5.1(1): "集合体は、ユーザ宣言されたコンストラクタ(12.1)、プライベートまたは保護された非静的データメンバ(11節)、基底クラス(10節)を持たない配列またはクラス(9節)仮想機能はありません(10.3)。
C ++では、Plain Old Dataは、int、charなどのようなものが使用される唯一の型であることを意味するのではありません。 プレーン・オールド・データは実際にはメモリ内のある場所から別の場所にmemcpy構造体を取ることができるということを意味しています。 これは、クラスまたはクラスに含まれるクラスが、ポインター、参照、または仮想関数を持つクラスであるメンバーとして存在する場合に、これを中断します。 本質的に、ポインタがどこかに関与しなければならない場合、ポインタは古いデータではありません。
POD(plain old data)オブジェクトは、コンストラクタを持たない基本データ型、ポインタ、共用体、構造体、配列、またはクラスのいずれかを持ちます。 逆に、非PODオブジェクトはコンストラクタが存在するオブジェクトです。 PODオブジェクトは、タイプの適切なサイズのストレージを取得し、オブジェクトのストレージが再利用または割り当て解除されたときにその存続期間が終了すると、その存続期間を開始します。
PlainOldData型には、次のいずれも指定できません。
- 仮想関数(独自の関数または継承された関数)
- 仮想基本クラス(直接的または間接的)。
PlainOldDataのより緩やかな定義には、コンストラクタを持つオブジェクトが含まれます。 仮想のものは除外しています。 PlainOldData型の重要な問題は、それらが非多形性であることです。 継承はPOD型で行うことができますが、ImplementationInheritance(コードの再利用)でのみ行い、多型/サブタイプでは行いません。
一般的な(厳密ではないが)定義は、PlainOldData型がVeeTableを持たないものであるということです。
要するに、すべての組み込みデータ型( int
、 char
、 float
、 long
、 unsigned char
、 double
など)とすべてのPODデータの集約です。 はい、再帰的な定義です。 ;)
より明確にするために、PODは「構造体」と呼ばれるものです。データを格納するユニットまたはユニットのグループです。
C ++ 11からC ++ 17までのstatic_assert
を持つ可能性のあるすべての非PODケースの例
std::is_pod
がC ++ 11で追加されました。だから、現在標準のものを考えてみましょう。
std::is_pod
は、 https://.com/a/48435532/895245 std::is_pod
述べたようにC ++ 20から削除されhttps://.com/a/48435532/895245 。これは、サポートが更新されたときに更新されhttps://.com/a/48435532/895245 。
標準が進化するにつれてPODの制限がますます緩和され、すべてのリラクゼーションをこの例でカバーすることを目指します。
libstdc ++は、 https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc : https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.ccでも小さなテストをしていhttps://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.ccが、ちょっと小さすぎる。 メンテナー:あなたがこの投稿を読んでいるなら、これをマージしてください。 私は、以下に挙げるすべてのプロジェクトをチェックするのは怠惰ですhttps://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers : https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers誰かがこのようなプロジェクトを作った場合、彼女は有名になるだろう。
あなたの編集、C + +の達人とすべての行方不明のTODOを殺すのを助けてください。
#include <type_traits>
#include <vector>
int main() {
/* POD restrictions have become more and more relaxed as the standard evolved.
*
* std::is_pod was added in C++11, so let's consider that standard onwards for now.
*/
#if __cplusplus >= 201103L
/* 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 i) {}
};
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& 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>());
}
/* 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 examples. Everything that does not fall in the non-POD examples. */
{
/* Can't get more POD than this. */
{
struct C {};
static_assert(std::is_pod<C>());
}
/* Private member: became POD in C++11
* https://.com/questions/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
}
/* Standard library containers are not, for the most part (all?),
* POD because they are not trivial, which can be seen directly from their
* interface definition in the standard.
* https://.com/questions/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>>());
}
/* Array of POD is POD. */
{
struct C {};
static_assert(std::is_pod<C>());
static_assert(std::is_pod<C[]>());
}
}
#endif
}
テスト済み:
for std in 11 14 17; do echo $std; g++-8 -std=c++$std pod.cpp; done
Ubuntu 18.04で
人に知られているすべてのPOD効果のリスト
すでにhttps://.com/a/4178176/895245リストがありhttps://.com/a/4178176/895245が、すべての例やリンクが必要な場合は、少なくとも編集してください:
-
__attribute__((packed))
は、非PODでは無視されます。非PODフィールドのためにパックされた属性を無視すると、そのようなクラスの安全なmemcpy
を防ぐことができます。
私が理解しているように、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から)
参照: