Trivial VS. Standard Layout VS. Pod

trivial vs. standard layout vs. POD

I don't think it can be done in truly layman's terms, at least without a lot of extra explanation. One important point is static vs. dynamic initialization, but explaining that to a layman would be several pages in itself...

PODs were (mis-)defined in C++98. There are really two separate intents involved, neither expressed very well: 1) that if you compile a C struct declaration in C++, what you get should be equivalent to what you had in C. 2) A POD will only ever need/use static (not dynamic) initialization.

C++0x/11 drops the "POD" designation (almost) entirely, in favor of "trivial" and "standard layout". Standard layout is intended to capture the first intent -- creating something with a layout the same as you'd get in C. Trivial is intended to capture the support for static initialization.

Since new T vs. new T() deals with initialization, you probably want is_trivial.

I'm not sure about compiler magic being required. My immediate reaction would be probably yes, but knowing some of the things people have done with TMP, I have a hard time being certain somebody couldn't do this too...

Edit: for examples, perhaps it's best to just quote the examples from N3290:

struct N { // neither trivial nor standard-layout
int i;
int j;
virtual ~N();
};

struct T { // trivial but not standard-layout
int i;
private:
int j;
};

struct SL { // standard-layout but not trivial
int i;
int j;
~SL();
};

struct POD { // both trivial and standard-layout
int i;
int j;
};

As you can undoubtedly guess, POD is also a POD struct.

Why is std::is_pod deprecated in C++20?

POD is being replaced with two categories that give more nuances. The c++ standard meeting in november 2017 had this to say about it:

Deprecating the notion of “plain old data” (POD). It has been replaced with two more nuanced categories of types, “trivial” and “standard-layout”. “POD” is equivalent to “trivial and standard layout”, but for many code patterns, a narrower restriction to just “trivial” or just “standard layout” is appropriate; to encourage such precision, the notion of “POD” was therefore deprecated. The library trait is_pod has also been deprecated correspondingly.

For simple data types use the is_standard_layout function, for trivial data types (such as simple structs) use the is_trivial function.

trivial and POD types with user-defined constructors

Yes, half is standard-layout (9/7): the base class is empty, the derived class has the same access control for all non-static data, there's nothing virtual and no non-standard-layout bases or members, and the base is a different type from the first non-static data member.

The constructors and assignment operators that you define are not copy (or move) constructors and assignments, so they have no bearing on whether the class is trivially copyable.

The default constructor is non-trivial because it is user-provided (12.1/5), and so the class is not trivial.

The copies/moves are all trivial because the data member and the empty base have trivial copies/moves (12.8/12). Same for the destructor, and so the class is trivially copyable.

So I believe your analysis is correct - remove the no-arg constructor and you have a POD class in C++11 (but not in C++98).

As Luc says, there is no guarantee in the standard that a POD class contains no padding, even if it has only one data member.

In C++03, the empty base class optimization is permitted, not required, so a poor-quality but conforming C++03 implementation could certainly give you sizeof(half) == sizeof(half_expr<half>) + sizeof(uint16_t). It is guaranteed that sizeof(half_expr<half>) > 0, and if it's smaller than uint16_t you could reasonably expect padding too.

In C++11, the rules on layout-compatibility in effect require that the empty base class optimization is applied -- two standard-layout types in which one has a base class and the other does not, are layout compatible (9.2/17), and layout-compatible types can be read through a union (9.2/19) which means they must have the same layout. Padding is still permitted, but pointless.

The standard aside, your implementation may or may not be working from a C++ ABI that tells you what POD classes look like. If so, I would expect that although the ABI might not be up-to-date for C++11 yet, surely the implementation will make all standard-layout classes look the way POD classes are defined to look, regardless of whether they are also trivial (and it will do the EBC optimization). That's kind of the point of standard-layout: "classes laid out like C structs".

I think that implementations are also permitted to arbitrarily decide that all class types must be 4-aligned, in which case again you'd get padding. I don't think it's reasonable to expect this, though, since the only motivation I can think of for doing it is that you're on some bizarre architecture where 4-aligned pointers can be smaller than char*.

Are members of a POD-struct or standard layout type guaranteed to be aligned according to their alignment requirements?

Each element of a POD struct is itself an object, and objects can only be allocated in accordance with the alignment requirements for those objects. The alignment requirements may change, though, due to the fact that something is a sub-object of another object ([basic.align]/1, 2:

1 Object types have alignment requirements (3.9.1, 3.9.2) which place restrictions on the addresses at which an object of that type may be allocated. An alignment is an implementation-defined integer value representing the number of bytes between successive addresses at which a given object can be allocated. An object type imposes an alignment requirement on every object of that type; stricter alignment can be requested using the alignment specifier (7.6.2).

2 A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported by the implementation in all contexts, which is equal to alignof(std::max_align_t) (18.2). The alignment required for a type might be different when it is used as the type of a complete object and when it is used as the type of a subobject. [Example:

struct B { long double d; };
struct D : virtual B { char c; }

When D is the type of a complete object, it will have a subobject of type B, so it must be aligned appropriately for a long double. If D appears as a subobject of another object that also has B as a virtual base class, the
B subobject might be part of a different subobject, reducing the alignment requirements on the D subobject.—end example ] The result of the alignof operator reflects the alignment requirement of the type in the
complete-object case.

[emphasis added]

Although the examples refer to a sub-object via inheritance, the normative wording just refers to sub-objects in general, so I believe the same rules apply, so on one hand you can assume that each sub-object is aligned so that it can be accessed. On the other hand, no you can't necessarily assume that will be the same alignment that alignof gives you.

[The reference is from N4296, but I believe the same applies to all recent versions. C++98/03, of course, didn't have alignof at all, but I believe the same basic principle applies--members will be aligned so they can be used, but that alignment requirement isn't necessarily the same as when they're used as independent objects.]

POD implications for a struct which holds an standard library container

No. Your basic assumptions are flawed. "Standard layout" is not related to templates. E.g. std::pair<T1, T2> has standard layout if and only if both T1 and T2 do. Same goes for std::array<T,N>

However, none of the Containers have standard layout. The whole point of their allocators is to have advanced memory management.

C++ : how do I use type_traits to determine if a class is trivial?

For std::memcpy it is sufficient that the type be trivially copyable. From n3290, 3.9 Types [basic.types] paragraph 2:

For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char.

Following paragraphs also describe other useful properties of trivially copyables types (i.e. not just copying to a char array).

std::is_trivially_copyable is the trait to detect just that. However as of my writing it's not implemented by e.g. GCC, so you may want to use std::is_trivial as a fallback (since in turn it requires a trivial copy constructor).

I really do not recommend using is_standard_layout, unless you really know what you're doing (e.g. language interoperability on one particular platform) it's not what you want. More information on what triviality and standard layout is about to perhaps help you specify the exact requirements you want.



Related Topics



Leave a reply



Submit