题
我遇到这个术语POD型几次。这是什么意思?
解决方案
POD 代表普通旧数据 - 即一个类(无论是使用关键字 struct
还是使用关键字类定义的)
)没有构造函数,析构函数和虚拟成员函数。 维基百科关于POD的文章详细介绍了一下,并将其定义为:
C ++中的普通旧数据结构是一个聚合类,它只包含PODS作为成员,没有用户定义的析构函数,没有用户定义的复制赋值运算符,也没有指向成员类型的非静态成员。
可以在 C ++ 98/03的答案中找到更多详细信息。 C ++ 11改变了围绕POD的规则,大大放松了它们,因此需要在此处提供后续答案。
其他提示
非常非正式:
荚是一种类型(包括类)里的C++编译器的保证,将不会有"魔术"会在本结构:例如隐藏的指针vtable都从、偏移,得到应用到该地址的时候它被铸造的其他类型(至少是如果目标的POD太),构造,或析构函数。大致说来,一个类型是POD当的唯一的东西它是建立在种类和组合。结果是"行为,如"C类型。
不非正式的方式:
int
,char
,wchar_t
,bool
,float
,double
都是豆荚,long/short
和signed/unsigned
版本。- 指针(包括针对功能和指针的成员)是豆荚,
enums
都是豆荚- 一个
const
或volatile
荚是POD。 - 一个
class
,struct
或union
的荚是POD提供的所有非静态数据成员public
, 和没有基类,并没有构造,析构或虚拟的方法。静态的成员不停止的东西是一个POD根据这一规则。这条规则已经改变C++11和某些私有成员都是允许的: 可以一类的所有私人成员被POD类? - 维基百科上是错误的说法,荚不能有成员的类型的指针的部件。或者说,这是正确的C++98措辞,但TC1明确,针对成员都POD。
正式(C++03标准):
3.9(10): "算类型(3.9.1),枚举的类型,指的类型,并指件类型(3.9.2)和简历资格的版本的这些类型(3.9.3)共同呼叫标类型。标类型,荚结构类型,荚联盟类型(第9条)、阵列的这种类型和简历资格的版本的这些类型(3.9.3)被统称为POD类型"
9(4): "一个荚结构是一个总的类,没有非静态数据的成员类型的非荚结构、非荚联盟(或阵列的这种类型)或参考,并没有用户定义的复制操作者和用户定义析构函数。同样,荚联盟是一个总的联盟,没有非静态数据的成员类型的非荚结构、非荚联盟(或阵列的这种类型)或参考,并没有用户定义的复制操作者和用户定义析构函数。
8.5.1(1): "总是一系列或类(第9条)没有用户宣布的构造(12.1),没有私人或受保护的非静态数据成员(第11条),不基类(第10条)和没有虚拟的功能(10.3)."
简而言之,它是所有内置数据类型(例如 int
, char
, float
, long
, unsigned char
, double
等)以及POD数据的所有聚合。是的,这是一个递归定义。 ;)
更清楚一点,POD就是我们所说的“结构”:一个单元或一组只存储数据的单元。
我的理解POD(PlainOldData)仅仅是一个原始数据-它不需要:
- 要构造,
- 被摧毁,
- 有定义的运营商。
- 必须不具有虚拟的功能,
- 并不复盖的运营商。
如何检查,如果东西是荚?嗯,有一个结构叫 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对象是一个为其一个构造的存在。荚对象开始其一生当它获得储存的适当大小的类型及其寿命结束时,储存的对象是重新使用或回收。
PlainOldData类型也必须没有任何:
- 虚拟的功能(或者是自己的,或继承)
- 虚拟基类(直接或间接).
一个宽松的定义PlainOldData包括对象造;但是不包括那些与的虚拟什么。这一重要问题与PlainOldData类型的是,他们是非多态的。继承权是可以做到与POD类型,但它只应用于ImplementationInheritance(代码重复使用),而不多态性/子类型.
一个常见的(虽然并不严格正确的)的定义是,一个PlainOldData类型是什么都没有VeeTable.
从C ++ 11到C ++ 17和POD效果的 static_assert
的所有非POD案例示例
std :: is_pod
,所以我们暂时考虑该标准。
std :: is_pod
将从C ++ 20中删除,如 https:// stackoverflow中所述.com / a / 48435532/895245 ,让我们在支持到达替换时更新此内容。
随着标准的发展,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 但它太少了。维护者:如果您阅读此帖,请合并。我懒得查看上面提到的所有C ++测试项目: https://softwareengineering.stackexchange.com/questions/199708/is-there-a-compliance-test-for-c-compilers
#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
// https://stackoverflow.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
}
// Most standard library containers are not POD because they are not trivial,
// which can be seen directly from their interface definition in the standard.
// https://stackoverflow.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>>(), "");
// Some might be though:
// https://stackoverflow.com/questions/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:
// https://stackoverflow.com/questions/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
// https://stackoverflow.com/questions/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上。
POD的概念和类型trait std :: is_pod
将在C ++ 20中弃用。有关详细信息,请参阅此问题。
为什么我们需要区分POD和非POD?
C ++作为C语言的延伸开始了它的生命。虽然现代C ++不再是C的严格超集,但人们仍然希望两者之间具有高度的兼容性。
粗略地说,POD类型是一种与C兼容的类型,也许同样重要的是与某些ABI优化兼容。
为了与C兼容,我们需要满足两个约束条件。
- 布局必须与相应的C类型相同。
- 必须以与相应C类型相同的方式将类型传递给函数并从函数返回。 醇>
某些C ++功能与此不兼容。
虚方法要求编译器插入一个或多个指向虚方法表的指针,这是C中不存在的。
用户定义的复制构造函数,移动构造函数,复制赋值和析构函数对参数传递和返回有影响。许多C ABI在寄存器中传递并返回小参数,但传递给用户定义的构造函数/ assigment /析构函数的引用只能用于内存位置。
因此需要定义可以预期“C兼容”的类型。什么类型不能。在这方面,C ++ 03有点严格。 C ++ 11打开了很多东西。
使用C ++,Plain Old Data并不仅仅意味着像int,char等这样的东西是唯一使用的类型。普通的旧数据在实践中确实意味着你可以将一个struct memcpy从内存中的一个位置转移到另一个位置,并且事情将完全像你期望的那样工作(即不会爆炸)。如果您的类或您的类包含的任何类具有作为指针或引用的成员或具有虚函数的类,则会中断。从本质上讲,如果指针必须涉及到某个地方,那么它不是普通的旧数据。