Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Standard Layout Classes and Trivially Copyable Types, Part II

Last updated Jan 1, 2003.

After explaining what standard layout classes are, this section will explore two other concepts: scalar types and trivially copyable classes.

Scalar Types

Scalar types include arithmetic types (integral types, floating types and bool), enumeration types, pointer types, pointer to member types, std::nullptr_t, and cv-qualified versions of these types. All scalar types are standard layout types, meaning their layout is specified. We will shortly discuss the importance of scalar types in the context object copying.

Byte-wise Copying of Objects

Certain standard functions (e.g., memcpy() and memmove()) and algorithms (e.g., std::copy()) can be used to copy objects by treating those objects as streams of bytes. This process can be useful for serializing objects, storing them in a database or when a C++ program transmits objects to a remote process. Byte-wise copying is guaranteed to work only if the object being copied has a trivially copyable type.

The C++11 standard also guarantees that for any object (other than a base-class subobject) of trivially copyable type T, the underlying bytes making up the object can be copied into an array of char or unsigned char (i.e., an array of bytes). If the content of that array is copied back into the object, the object shall subsequently hold its original value:

#define N sizeof(T)
char buf[N]={0};
T obj; 
std::memcpy(buf, &obj, N); 
//change the value of the original object
std::memcpy(&obj, buf, N); //obj returns to its original state

This technique can also be used with two distinct objects of any trivially copyable type T. For example, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the underlying bytes making up obj1 are copied into obj2, obj2 shall subsequently hold the same value as obj1:

T* t1p = &obj1;
T* t2p = obj2;
std::memcpy(t1p, t2p, sizeof(T));

Byte-wise copying is used in every networking protocol and cross-language API (e.g., JNI).

Now that we've learned why trivially copyable types are so important, let's see what they are exactly.

Trivially Copyable Classes

A trivially copyable class is a class that:

  • has no non-trivial copy constructors.
  • has no non-trivial move constructors.
  • has no non-trivial copy assignment operators.
  • has no non-trivial move assignment operators.
  • has a trivial destructor.

If the sequence "no non-trivial" sounds confusing, recall logic 101: double negation is redundant. Therefore, the cumbersome phrase "has no nontrivial x" is more or less interchangeable with "has trivial x".

In simpler words, a class whose four copy-or-move special member functions are all trivial, and whose destructor is also trivial — is a trivially copyable class. In particular, a trivially copyable class does not have virtual functions or virtual base classes. On that note, recall that deleted special member functions aren't trivial. Therefore, if a class has a deleted destructor or a deleted copy-or-move special member function, it's not a trivially copyable class.

All scalar types are trivially copyable types because they meet the above five requirements. This means that byte-wise copying of scalar variables is safe. Here's a slightly modified version of the previous code example that illustrates this point:

double obj1=15.66, obj2=0.5;
double* t1p = &obj1;
double* t2p = obj2;
std::memcpy(t1p, t2p, sizeof(double));

After the memcpy() call, both obj1 and obj2 have the same value of 0.5.

Finally, a trivial class is a class that has a trivial default constructor and is trivially copyable.

In Conclusion

Standard layout classes are ones whose layout, in terms of their members' number and their relative ordering, is specified. Trivially copyable classes have standard layout. However, in addition they do not involve any special copying semantics (such as deep copying, copy-on-write, or even an implementation-defined copy constructor) so you can capture their state by copying them into byte arrays using byte-oriented copy functions and algorithms. Similarly, you can use byte-wise copying to assign the state of one object to another if both objects have the same type and they are non-base class objects of a trivially copyable type. Finally, scalar types are both trivially copyable and have standard layout. The importance of the scalar types concept is that standard layout objects are made up of members that are scalar types.