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


977

我已经多次遇到过这个术语POD类型。
这是什么意思?



5
请参阅 chat.stackoverflow.com/transcript/message/213026#213026和第二天的消息来讨论接受的答案
Johannes Schaub-litb 2010年


@ paxos1977:请更改对“解决方案”(当前是Hewgill的答案)的选择,以使根本上错误的答案不会误导那些到此为止的Google员工。
干杯和健康。-Alf

我们得出的结论是,c风格的字符串不是POD类型,因为1.)指针与字符串数据不连续,并且2.)为了使字符串成为POD类型,您需要确保类型在POD类型的预定义大小内包含零项字符,从而导致未定义的行为。

Answers:


694

POD代表普通旧数据 -即不带构造函数,析构函数和虚拟成员函数的类(无论是使用关键字struct还是使用关键字定义class)。Wikipedia上有关POD的文章更加详细,并将其定义为:

C ++中的Plain Old Data Structure是一个聚合类,它仅包含PODS作为成员,没有用户定义的析构函数,没有用户定义的副本分配运算符,并且没有指针到成员类型的非静态成员。

C ++ 98/03的答案中可以找到更多详细信息。C ++ 11更改了围绕POD的规则,大大放松了它们,因此需要在此处进行后续解答


34
有区别。内在类型是“内置”语言原语。这些是POD类型,再加上这些(和其他POD)的聚合。
亚当·赖特

59
POD类型具有非POD类型所没有的特征。例如,如果您具有全局,const,POD类型的结构,则可以使用大括号表示法初始化其内容,将其放入只读存储器中,并且无需生成任何代码即可对其进行初始化(构造函数或其他形式),因为它是程序映像的一部分 这对于经常在RAM,ROM或Flash上​​有严格限制的嵌入式人员来说非常重要。
Mike DeSimone

34
在C ++ 11中,您可以执行std :: is_pod <MyType>()来判断MyType是否为POD。
allyourcode 2014年

7
Bjarne Stroustrup的C ++性能技术报告指出,C ++标准将POD描述为“ 与布局,初始化及其通过memcpy复制的功能与C中的等效数据类型兼容的数据类型 ”。也许应该在POD类型和POD结构之间进行区分。
user34660 2015年

6
−1截至2016年8月16日,此答案从根本上仍然是错误且具有误导性:POD类型不限于类类型。
干杯和健康。-Alf

352

非常非正式地:

POD是一种类型(包括类),在这种类型中,C ++编译器保证结构中不会发生“魔术”现象:例如,指向vtables的隐藏指针,将其转换为其他类型时应用于地址的偏移量(至少是目标的POD),构造函数或析构函数。粗略地说,当类型中的唯一内容是内置类型及其组合时,它就是POD。结果是“类似于” C类型的行为。

非正式地:

  • intcharwchar_tboolfloatdouble是豆荚,因为是long/shortsigned/unsigned他们的版本。
  • 指针(包括指向功能的指针和指向成员的指针)是POD,
  • enums 是POD
  • 一个constvolatilePOD是POD。
  • 一个classstructunion荚果的是一个POD条件是所有的非静态数据成员是public,它没有基类和没有构造,析构函数,或虚拟方法。在此规则下,静态成员不会阻止某些东西成为POD。此规则在C ++ 11中已更改,并且允许某些私有成员:具有所有私有成员的类可以是POD类吗?
  • 维基百科说POD不能具有指针指向成员类型的成员是错误的。或者更确切地说,这对于C ++ 98的措词是正确的,但是TC1明确指出成员指针是POD。

正式(C ++ 03标准):

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-union是一个聚合联合,它不具有非POD-struct,non-POD-union(或此类数组)或引用类型的非静态数据成员,并且没有用户定义的复制运算符,也没有用户定义的析构函数。

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


3
您有正式/不太正式。您可以添加经验法则。内置类型和内置类型的聚合(或类似的东西)。除了获得准确的定义,我们还需要使知识易于使用。
马丁·约克

1
您在“将类型转换为其他类型时的偏移量”位上错了一点。当转换为基类或派生类时,将应用这些偏移量。因此,如果从POD基类指针转换为非POD派生类,则可能仍会遇到调整。
MSalters

1
@Steve Jessop:为什么我们需要完全区分POD和非POD?
Lazer 2010年

6
@Lazer:这是另一个问题,“ POD的行为如何?” 而不是“ POD是什么意思?”。总而言之,差异涉及初始化(因此也使用memcpy复制对象),与该编译器的C结构布局兼容以及指针上下转换。POD的行为类似于C类型,非POD不能保证做到这一点。因此,如果您希望您的类型像C结构那样可移植地运行,则必须确保它是POD,因此您需要了解不同之处。
史蒂夫·杰索普

4
@muntoo:确实,我确实在评论引用维基百科过时信息的答案。我想我可以编辑该答案,但是如果我回想编辑别人的答案以同意我的观点,我会感到麻烦,无论我认为我有多正确。
史蒂夫·杰索普

20

原始数据

总之,它是所有内置的数据类型(例如intcharfloatlongunsigned chardoublePOD的数据,等等)和所有聚集。是的,这是一个递归定义。;)

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


12
的确,我们有时称它们为“结构”。但是,这样做总是错误的,因为结构不一定是POD类型。
史蒂夫·杰索普

6
显然...结构和类几乎相等,但是在“业务”中,我们称“结构”为简单的数据收集器,通常没有ctor和dtor,通常具有值语义...
ugasoft

2
对我来说,使struct与class关键字相同或接近是C ++错误:struct仅将公共默认访问权限添加到class。我更容易制作类似C的结构,并且在c ++的第0天我们会拥有POD。
user1708042's

ugasoft:您的答案可能会误导您-您的评论解释了缺少的细节,该细节在实践中像常规用法一样,而不是标准用法。哇,八岁了,你还在这里吗?;-)
hauron

字符串除外,因为您必须先确定字符串长度才能使用memcpy复制它。

12

据我了解,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)


参考:


2
不正确的是,POD类型可能具有成员函数或重载的运算符。(但它可能没有虚拟成员函数。)
Colin D Bennett

@ColinDBennett是的,是的。对困惑感到抱歉。编辑进/出anwser。
набиячлэвэли

10

POD(普通旧数据)对象具有以下数据类型之一(基本类型,指针,联合,结构,数组或类),而没有构造函数。相反,非POD对象是为其构造函数的对象。POD对象在获得具有适合其类型的大小的存储空间时开始其生存期,而当该对象的存储空间被重新使用或释放​​时,其生存期结束。

PlainOldData类型也不得具有以下任何一种:

  • 虚函数(自己的或继承的)
  • 虚拟基类(直接或间接)。

对PlainOldData的较宽松定义包括带有构造函数的对象。但排除具有虚拟事物的人。PlainOldData类型的重要问题是它们是非多态的。可以使用POD类型进行继承,但是仅应对ImplementationInheritance(代码重用)进行继承,而不应该对多态性/子类型进行继承。

一个普通的(尽管不是严格正确的)定义是PlainOldData类型是没有VeeTable的任何类型。


您的答案非常好,但是这个问题已经在8年前接受了答案,另外还有几个其他好的答案。如果您使用自己的知识来回答尚未回答的问题,则可以为SO做出更大的贡献)))
mvidelgauz,2016年

10

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

C ++作为C的扩展开始了它的生命。尽管现代C ++不再是C的严格超集,但人们仍然期望两者之间具有高度的兼容性。

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

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

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

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

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

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

因此,需要定义哪些类型可以期望是“ C兼容的”,哪些类型不能。在这方面,C ++ 03有点过分严格,任何用户定义的构造函数都将禁用内置的构造函数,并且任何将它们添加回的尝试都将导致它们是用户定义的,因此类型是非Pod。通过允许用户重新引入内置构造函数,C ++ 11大大提高了性能。


8

具有static_assertC ++ 11至C ++ 17和POD效果的所有非POD情况的示例

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

std::is_podhttps://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但太少了。维护人员:如果您阅读此文章,请合并此内容。我很懒惰地查看以下提到的所有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
        // /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
}

GitHub上游

经过测试:

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



-7

使用C ++,普通的旧数据不仅意味着int,char等是唯一使用的类型。普通旧数据实际上意味着在实践中,您可以将其从内存中的一个位置转移到另一位置,并且事情将按预期运行(即不会崩溃)。如果您的类或您的类包含的任何类的成员是指针或引用或具有虚函数的类,则这会中断。本质上,如果指针必须包含在某个地方,则它不是普通的旧数据。


6
POD结构中允许使用指针。引用不是。
j_random_hacker

1
此处缺少Passant。
icbytes 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.