C ++中的POD类型是什么?

时间:2008-09-28 18:36:10

标签: c++ types c++-faq

我几次遇到这个术语POD类型。 这是什么意思?

8 个答案:

答案 0 :(得分:620)

POD 代表普通旧数据 - 即一个类(无论是使用关键字struct还是使用关键字class定义),而不是构造函数,析构函数和虚拟成员函数。 Wikipedia's article on POD更详细地介绍了它,并将其定义为:

  

C ++中的普通旧数据结构是一个聚合类,它只包含PODS作为成员,没有用户定义的析构函数,没有用户定义的复制赋值运算符,也没有指向成员类型的非静态成员。

可在this answer for C++98/03中找到更详细的信息。 C ++ 11改变了围绕POD的规则,大大放松了它们,因此necessitating a follow-up answer here

答案 1 :(得分:319)

非正式地说:

POD是一种类型(包括类),其中C ++编译器保证结构中不会出现“魔法”:例如隐藏指向vtable的指针,当转换为地址时应用于地址的偏移量其他类型(至少如果目标的POD也是如此),构造函数或析构函数。粗略地说,类型是POD,当它中的唯一内容是内置类型和它们的组合时。结果就像“C型”一样。

不那么非正式地:

  • intcharwchar_tboolfloatdouble是POD,long/short和{ {1}}版本。
  • 指针(包括指向函数的指针和指向成员的指针)是POD,
  • signed/unsigned是POD
  • enumsconst POD是POD。
  • POD的volatileclassstruct是POD,前提是所有非静态数据成员都是union,并且它没有基类,也没有构造函数,析构函数或虚拟方法。静态成员不会在此规则下停止某个POD。此规则在C ++ 11中已更改,并且允许某些私有成员:Can a class with all private members be a POD class?
  • 维基百科说POD不能包含指向成员的类型成员是错误的。或者更确切地说,它对于C ++ 98的措辞是正确的,但TC1明确指出成员指针是POD。

形式上(C ++ 03标准):

  

3.9(10):“算术类型(3.9.1),枚举类型,指针类型和指向成员类型(3.9.2)的指针以及这些类型的cv限定版本(3.9) .3)是统一的调用者标量类型。标量类型,POD结构类型,POD-union类型(第9节),这些类型的数组和这些类型的cv限定版本(3.9.3)统称为POD类型“< / p>      

9(4):“POD-struct是一个聚合类,它没有非POD-struct类型的非静态数据成员,非POD-union(或者这样的数组)类型)或引用,没有用户定义的复制操作符,也没有用户定义的析构函数。类似地,POD-union是一个聚合联合,它没有非POD-struct,非POD-union类型的非静态数据成员(或此类型的数组)或引用,并且没有用户定义的复制操作符,也没有用户定义的析构函数。

     

8.5.1(1):“聚合是一个数组或类(第9节),没有用户声明的构造函数(12.1),没有私有或受保护的非静态数据成员(子句) 11),没有基类(第10节)和虚函数(10.3)。“

答案 2 :(得分:17)

Plain Old Data

简而言之,它是所有内置数据类型(例如intcharfloatlongunsigned char,{{1}等等)和POD数据的所有聚合。是的,这是一个递归定义。 ;)

更清楚一点,POD就是我们所说的“结构”:一个单元或一组只存储数据的单元。

答案 3 :(得分:10)

据我所知,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)>
  { };
}

(来自标题类型_traits)


参考:

答案 4 :(得分:6)

从C ++ 11到C ++ 17的所有static_assert非POD案例示例和POD效果

std::is_pod是在C ++ 11中添加的,因此现在就考虑该标准。

std::is_pod将如https://stackoverflow.com/a/48435532/895245中所述从C ++ 20中删除,让我们对其进行更新,以支持替换。

随着标准的发展,POD限制变得越来越宽松,我打算通过ifdefs涵盖示例中的所有放松。

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://softwareengineering.stackexchange.com/questions/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
        // 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
}

GitHub upstream

经过测试:

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上。

答案 5 :(得分:3)

POD的概念和类型特征std::is_pod将在C ++ 20中弃用。有关详细信息,请参阅this问题。

答案 6 :(得分:2)

  

为什么我们需要完全区分POD和非POD?

C ++最初是C的扩展。尽管现代C ++不再是C的严格超集,但人们仍然期望两者之间具有高度的兼容性。

粗略地说,POD类型是与C兼容的类型,也许同样重要的是与某些ABI优化兼容的类型。

要与C兼容,我们需要满足两个约束。

  1. 布局必须与相应的C类型相同。
  2. 必须以与相应的C类型相同的方式将类型传递给函数并从中返回。

某些C ++功能与此不兼容。

虚拟方法要求编译器插入一个或多个指向虚拟方法表的指针,这在C语言中是不存在的。

用户定义的副本构造函数,移动构造函数,副本分配和析构函数对参数传递和返回有影响。许多C ABI在寄存器中传递并返回较小的参数,但传递给用户定义的构造函数/辅助函数/析构函数的引用只能与内存位置一起使用。

因此,需要定义哪些类型可以期望是“ C兼容的”,哪些类型不能。在这方面,C ++ 03有点过分严格。 C ++ 11大大提高了性能。

答案 7 :(得分:-6)

使用C ++,Plain Old Data并不仅仅意味着像int,char等这样的东西是唯一使用的类型。普通的旧数据在实践中确实意味着你可以将一个struct memcpy从内存中的一个位置转移到另一个位置,并且事情将完全像你期望的那样工作(即不会爆炸)。如果您的类或您的类包含的任何类具有作为指针或引用的成员或具有虚函数的类,则会中断。从本质上讲,如果指针必须涉及到某个地方,那么它不是普通的旧数据。