What are POD types in C++? [duplicate]
Asked Answered
G

9

1221

I've come across this term POD-type a few times.
What does it mean?

Gulick answered 28/9, 2008 at 18:36 Comment(7)
Also see http://stackoverflow.com/questions/2293796Hootchykootchy
please see chat.stackoverflow.com/transcript/message/213026#213026 and the following day's messages for discussion about the accepted answerIsrael
Also stackoverflow.com/questions/4178175/…Applause
@paxos1977: Please change your selection of "solution" (currently Hewgill's answer) so that a fundamentally wrong answer doesn't mislead googlers who end up here.Chthonian
We've concluded that a c-style string is NOT a POD type because 1.) the pointer is not contiguous with the string data, and 2.) in order to make a string a POD type, you would need to ensure the type had a nil-term char in it within the predefined size of the POD type, leading to undefined behavior.Raincoat
@Raincoat what do you mean, and who are we? There is pointer to string and storage where array of chars is located, both are treated as trivial data. Structure which contains pointer to char is still a POD, the fact that it doesn't own string's storage is a different, unrelated fact.Hideous
This Q&A is now largely obsolete. The superset Q&A has questions of equal or greater quality. The term POD has been superseded in C++11 and deprecated in C++20 and should no longer be used in general, and this Q&A doesn't inform users about these version changes to sufficient extent. It's interesting from a historical perspective.Magnesite
A
852

POD stands for Plain Old Data - that is, a class (whether defined with the keyword struct or the keyword class) without constructors, destructors and virtual members functions. Wikipedia's article on POD goes into a bit more detail and defines it as:

A Plain Old Data Structure in C++ is an aggregate class that contains only PODS as members, has no user-defined destructor, no user-defined copy assignment operator, and no nonstatic members of pointer-to-member type.

Greater detail can be found in this answer for C++98/03. C++11 changed the rules surrounding POD, relaxing them greatly, thus necessitating a follow-up answer here.

Alexandrite answered 28/9, 2008 at 18:37 Comment(16)
Hmmm... I guess I prefer more correct technical term of "intrinsic type" to this kind of slang. ;)Gulick
There's a difference. Intrinsic types are the "builtin" language primitives. POD types are these, plus aggregations of these (and other PODs).Ackerman
POD: int,char,float etc. The built in types.Tiossem
@Greg Hewgill: Why do we need to differentiate between POD's and non-POD's at all?Hootchykootchy
POD types have characteristics that non-POD types do not. For example, if you have a global, const, POD-type struct, you can initialize its contents with brace notation, it is put into read-only memory, and no code needs to be generated to initialize it (constructor or otherwise), because it's part of the program image. This is important for embedded folks who often have tight constraints on RAM, ROM, or Flash.Herein
In C++11, you can do std::is_pod<MyType>() to tell whether MyType is POD.Leeway
Bjarne Stroustrup's Technical Report on C++ Performance states that the C++ standard describes a POD as being "a data type which is compatible with the equivalent data type in C in layout, initialization, and its ability to be copied with memcpy". Perhaps a distinction should be made between a POD type and a POD structure.Neuropsychiatry
−1 This answer is still fundamentally wrong & misleading as of 16th Aug 2016: POD types are not restricted to be class types.Chthonian
What about a string? Strings are in C, but you can't just copy them with memcpy.Raincoat
A string by default is a ASCII string, and UTF-8 is a not built-in. A string could use a UTF-8 base class with a UTF-16 and UTF-32 subclass. By this definition, not all strings are POD types. If not all strings are POD types, then strings by definition would not be a POD type. No one mentions strings in the POD argument probably for this very reason. Where are the doctors?Raincoat
So then by that definition then a String is not a POD because you cannot copy it directly with memcpy.Raincoat
@Cale There's no such thing as a "string" type in C. There's a char *, but the vital distinction there is that while the type itself is in fact a POD type, its conceptual value -- i.e. what you think of it representing, that array of characters -- isn't POD, for the reasons you give. The actual pointer itself, the char * you pass around, is basically an integer in fancy dress, and works give-or-take the same as an int for the purposes if figuring if something is a POD type. However, to copy the conceptual string that it represents, yes, you need to do more.Margie
@NicHartley: That's a critical point. An array of characters is a POD, and in C, that's all you've got. The concept of a "string" is an artifact of a library of functions that process zero-terminated arrays of characters.Exobiology
POD sounds quite similar to blittable types of C#Valuator
This answer is very incomplete and can be misleading. A POD is not necessarily a POD Class. It could be an array, it could be a scalar, etc. It's much more nuanced. See this for a detailed breakdown.Mastin
Isn't your text contradicting with the quote you have put after it? I mean in the "no constructors" part?Celia
L
424

Very informally:

A POD is a type (including classes) where the C++ compiler guarantees that there will be no "magic" going on in the structure: for example hidden pointers to vtables, offsets that get applied to the address when it is cast to other types (at least if the target's POD too), constructors, or destructors. Roughly speaking, a type is a POD when the only things in it are built-in types and combinations of them. The result is something that "acts like" a C type.

Less informally:

  • int, char, wchar_t, bool, float, double are PODs, as are long/short and signed/unsigned versions of them.
  • pointers (including pointer-to-function and pointer-to-member) are PODs,
  • enums are PODs
  • a const or volatile POD is a POD.
  • a class, struct or union of PODs is a POD provided that all non-static data members are public, and it has no base class and no constructors, destructors, or virtual methods. Static members don't stop something being a POD under this rule. This rule has changed in C++11 and certain private members are allowed: Can a class with all private members be a POD class?
  • Wikipedia is wrong to say that a POD cannot have members of type pointer-to-member. Or rather, it's correct for the C++98 wording, but TC1 made explicit that pointers-to-member are POD.

Formally (C++03 Standard):

3.9(10): "Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to member types (3.9.2) and cv-qualified versions of these types (3.9.3) are collectively caller scalar types. Scalar types, POD-struct types, POD-union types (clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD types"

9(4): "A POD-struct is an aggregate class that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-define copy operator and no user-defined destructor. Similarly a POD-union is an aggregate union that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-define copy operator and no user-defined destructor.

8.5.1(1): "An aggregate is an array or class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10) and no virtual functions (10.3)."

Launder answered 28/9, 2008 at 19:48 Comment(13)
You have formal/less formal. You could add rule of thumb. Built in types and aggregations of Built in types (or something like that). In addition to get the exact definition we need to make the knowledge easy to use.Tiossem
I've added a "roughly speaking" clause. I don't want to say "aggregate" because it's a jargon term, and a casual reader wouldn't know that it means no virtual functions, no private members, etc.Launder
You're a bit wrong on the "offsets when cast_to another type" bit. Those offsets are applied when casting to a base or derived class. So, if you cast from a POD base class pointer to a non-POD derived class, you may still encounter an adjustement.Attica
@Steve Jessop: Why do we need to differentiate between POD's and non-POD's at all?Hootchykootchy
@Lazer: that's a whole other question, "how do PODs behave?" as opposed to "what does POD mean?". In summary the difference relates to initialisation (hence also use of memcpy to duplicate objects), compatibility with C struct layout for that compiler, and pointer up- and down-casting. PODs "act like C types", non-PODs aren't guaranteed to do so. So if you want your type to portably act like a C struct, you must ensure that it is POD, so you need to know the difference.Launder
@Lazer: A (belated, but) very comprehensive reply can be found here: stackoverflow.com/questions/4178175/…Demark
I like this one. I wish this one would have been accepted. Very nice! I like how the first paragraph fits the description of "POF" too ("plain old function", a term also defined by the Standard).Israel
@muntoo: it has been, really I was commenting on the answer that quotes outdated info from Wikipedia. I could edit that answer, I suppose, but I smell trouble if I go around editing other people's answer to agree with mine, no matter how right I think I am.Launder
So then is a string a POD type or what? All of the posts don't touch the subjects with a 10 foot pole. It's the question EVERYONE wants to know... Yes a ASCII string IS a built-in type, but what about a UTF-16 or UTF-32 string? Those aren't built-in, but are still strings,and there COULD be magic going on behind the scenes with OO programming techniques (i.e. abstract string stored as UTF-8 then sub-classed to UTF-16 or UTF-32). If one type of string is not a POD type, then all of them aren't POD types by induction.Raincoat
@Cale: the C++ string types all have constructors, so in the C++03 definition they are not aggregates and hence not POD. Likewise, my "very informally" and "less informally" definitions both state that classes cannot be POD if they have a constructor. For a given standard class, you can check whether or not it has constructors, destructors, virtual member functions, base classes, or copy operators, by reading the spec for that class (or class template).Launder
The conclusion me and a doctor of CS friend came to was that you could "pretend" a string is a POD type, but in order to ensure the nil-term char is there, it would require a constructor. You would just get undefined behavior.Raincoat
@Cale: pretend what you like :-) There are several things you're allowed to do with POD that won't work with strings. Using them without construction is one, but freeing the memory without first destructing the object is another, and copying the object to a new location and using it there is a third.Launder
You mention "vtables" but don't explain them. Here's some great info. on vptrs and vtbls: drdobbs.com/cpp/storage-layout-of-polymorphic-objects/240012098.Volga
C
30

Plain Old Data

In short, it is all built-in data types (e.g. int, char, float, long, unsigned char, double, etc.) and all aggregation of POD data. Yes, it's a recursive definition. ;)

To be more clear, a POD is what we call "a struct": a unit or a group of units that just store data.

Cartwright answered 28/9, 2008 at 18:41 Comment(8)
It's true that we sometimes call them 'a struct'. However we're always wrong to do so, since a struct is not necessarily a POD-type.Launder
obviously... struct and class are almost equivalent, but in "the business" we call 'a struct' a simple data collector, usually without ctors and dtor, usually with value semantics...Cartwright
For me it was C++ wrong to make struct identical to the class keyword or close to: struct only adds public default access to class. I was simpler to make C-like structs and we would have had PODs on day 0 of c++.Scriber
ugasoft: your answer may be misleading - your comment explained the missing detail that it is used like that in practice, rather than standard. Whoa, 8 years, are you even here? ;-)Montmartre
With the exception of a string because you can't copy it with memcpy without first determining the string length.Raincoat
@Cartwright actually struct and class are not equivalent, because all variables declared in a struct is public, whereas in a class you can have private variables as well, so using struct can led to security problems in the long run, that is why they are not used very often in OOP.Keitel
Can anyone clarify for me what ctors and dtor are because I have never seen them in structs or seen a struct referred to as a simple data collector???Keitel
@Scriber Well, the reason why struct and class are identical, save for default access qualifier, is that, under the C++ compiler hood, the implementation of a class really is just a struct. Methods really are just functions that take "a pointer to a struct" (a.k.a. "this") to access that instance of the struct as the first parameter, and "virtual tables" are just function pointers inside that struct (so they can be changed). The only reason to add the "class" keyword was because C "structs" are public by default, which violates the OOP "black box" principle.Vesica
B
25

Why do we need to differentiate between POD's and non-POD's at all?

C++ started its life as an extension of C. While modern C++ is no longer a strict superset of C, people still expect a high level of compatibility between the two. The "C ABI" of a platform also frequently acts as a de-facto standard inter-language ABI for other languages on the platform.

Roughly speaking, a POD type is a type that is compatible with C and perhaps equally importantly is compatible with certain ABI optimisations.

To be compatible with C, we need to satisfy two constraints.

  1. The layout must be the same as the corresponding C type.
  2. The type must be passed to and returned from functions in the same way as the corresponding C type.

Certain C++ features are incompatible with this.

Virtual methods require the compiler to insert one or more pointers to virtual method tables, something that doesn't exist in C.

User-defined copy constructors, move constructors, copy assignments and destructors have implications for parameter passing and returning. Many C ABIs pass and return small parameters in registers, but the references passed to the user defined constructor/assigment/destructor can only work with memory locations.

So there is a need to define what types can be expected to be "C compatible" and what types cannot. C++03 was somewhat over-strict in this regard, any user-defined constructor would disable the built-in constructors and any attempt to add them back in would result in them being user-defined and hence the type being non-pod. C++11 opened things up quite a bit, by allowing the user to re-introduce the built-in constructors.

Bochum answered 29/11, 2018 at 18:17 Comment(0)
R
16

Examples of all non-POD cases with static_assert from C++11 to C++17 and POD effects

std::is_pod has been added in C++11, so let's consider that standard onwards for now.

std::is_pod has been deprecated C++20 as mentioned at https://mcmap.net/q/17069/-what-are-pod-types-in-c-duplicate , let's update this as support arrives for the replacements.

POD restrictions have become more and more relaxed as the standard evolved, I aim to cover all relaxations in the example through ifdefs.

libstdc++ has at tiny bit of testing at: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.cc but it just too little. Maintainers: please merge this if you read this post. I'm lazy to check out all the C++ testsuite projects mentioned at: 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://mcmap.net/q/17269/-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://mcmap.net/q/17270/-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://mcmap.net/q/17271/-is-std-array-lt-t-s-gt-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://mcmap.net/q/17268/-what-are-aggregates-and-trivial-types-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://mcmap.net/q/17272/-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.

Tested with:

for std in 11 14 17; do echo $std; g++-8 -Wall -Werror -Wextra -pedantic -std=c++$std pod.cpp; done

on Ubuntu 18.04, GCC 8.2.0.

Rodmur answered 25/10, 2018 at 12:51 Comment(0)
B
11

As I understand POD (PlainOldData) is just a raw data - it does not need:

  • to be constructed,
  • to be destroyed,
  • to have custom operators.
  • Must not have virtual functions,
  • and must not override operators.

How to check if something is a POD? Well, there is a struct for that called 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)>
  { };
}

(From header type_traits)


Reference:

Balmung answered 7/12, 2013 at 21:38 Comment(2)
Incorrect, a POD type may have member functions or overloaded operators. (But it may not have virtual member functions.)Polaroid
@ColinDBennett Yeah, that's true. Sorry for the confusion. Edited into/out of the anwser.Grope
P
10

A POD (plain old data) object has one of these data types--a fundamental type, pointer, union, struct, array, or class--with no constructor. Conversely, a non-POD object is one for which a constructor exists. A POD object begins its lifetime when it obtains storage with the proper size for its type and its lifetime ends when the storage for the object is either reused or deallocated.

PlainOldData types also must not have any of:

  • Virtual functions (either their own, or inherited)
  • Virtual base classes (direct or indirect).

A looser definition of PlainOldData includes objects with constructors; but excludes those with virtual anything. The important issue with PlainOldData types is that they are non-polymorphic. Inheritance can be done with POD types, however it should only be done for ImplementationInheritance (code reuse) and not polymorphism/subtyping.

A common (though not strictly correct) definition is that a PlainOldData type is anything that doesn't have a VeeTable.

Piddling answered 16/8, 2016 at 11:56 Comment(1)
Yuor answer is very good, but this question has accepted answer 8 years ago, plus several other good answers. You can contribute more to SO if you use you knowledge to answer questions that are not yet answered )))Diamine
V
4

The concept of POD and the type trait std::is_pod has been deprecated in C++20. See Why is std::is_pod deprecated in C++20? for further information.

Vellavelleity answered 25/1, 2018 at 4:9 Comment(0)
C
-7

With C++, Plain Old Data doesn't just mean that things like int, char, etc are the only types used. Plain Old Data really means in practice that you can take a struct memcpy it from one location in memory to another and things will work exactly like you would expect (i.e. not blow up). This breaks if your class, or any class your class contains, has as a member that is a pointer or a reference or a class that has a virtual function. Essentially, if pointers have to be involved somewhere, its not Plain Old Data.

Camala answered 28/9, 2008 at 20:14 Comment(2)
Pointers are allowed in POD structs. References aren't.Veats
Passant is missing here.Teacake

© 2022 - 2024 — McMap. All rights reserved.