28

My question is the following:

If I want to copy a class type, memcpy can do it very fast. This is allowed in some situations.

We have some type traits:

  • is_standard_layout.
  • is_trivially_copyable.

What I would like to know is the exact requirements when a type will be "bitwise copyable".

My conclusion is that a type is bitwise copyable if both of is_trivally_copyable and is_standard_layout traits are true:

  1. It is exactly what I need to bitwise copy?
  2. Is it overconstrained?
  3. Is it underconstrained?

P.S.: of course, the result of memcpy must be correct. I know I could memcpy in any situation but incorrectly.

Germán Diago
  • 7,473
  • 1
  • 36
  • 59
  • 2
    The assignment operator can copy just as fast, you know. As a bonus, it still works if you ever change your class to be non-trivially-copyable. – Benjamin Lindley Nov 19 '14 at 05:13
  • 2
    Do you actually need to use `memcpy` for some particular reason other than speed? Because you can get the same speed from the compiler while retaining type safety just by using the default copy ctor/assignment operator. For trivially copyable types, even very high level things like `std::copy` on an array of your trivially copyable type would be optimized to a single `memcpy`. – Nicu Stiurca Nov 19 '14 at 05:15
  • It is just to understand the inner workings. – Germán Diago Nov 19 '14 at 05:39
  • It's quite common that the default copy is _faster_ than the `memcpy function` because it can skip all kind of misalignment checks. That's why compilers often implement `memcpy` as an intrinsic, to make it as fast as the default copy constructors. – MSalters Nov 19 '14 at 10:24
  • @NicuStiurca: I got here because I need a container for arbitrary such data. By using enabled if, I can stop people from constructing messages that cannot be copied in a trivial way. – user877329 May 22 '16 at 10:34

5 Answers5

26

You can copy an object of type T using memcpy when is_trivially_copyable<T>::value is true. There is no particular need for the type to be a standard layout type. The definition of 'trivially copyable' is essentially that it's safe to do this.

An example of a class that is safe to copy with memcpy but which is not standard layout:

struct T {
  int i;
private:
  int j;
};

Because this class uses different access control for different non-static data members it is not standard layout, but it is still trivially copyable.

Jack
  • 131,802
  • 30
  • 241
  • 343
bames53
  • 86,085
  • 15
  • 179
  • 244
14

If is_trivally_copyable<T>::value (or in C++14 is_trivially_copyable<T>(), or in C++17 is_trivially_copyable_v<T>) is not zero, the type is copyable using memcpy.

Per the C++ standard, a type being trivially copyable means:

the underlying bytes making up the object can be copied into an array of char or unsigned char. If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value.

However, it is important to realise that pointers are trivially copyable types, too. Whenever there are pointers inside the data structures you will be copying, you have to brainually make sure that copying them around is proper.

Examples where hazard may be caused by just relying on the object being trivially copyable:

  • A tree-structure implementation where your data is placed in a contiguous region of memory, but with nodes storing absolute addresses to child nodes
  • Creating multiple instances of some data for sake of multithreading performance (in order to reduce cache crashes), with owning pointers inside, pointing anywhere
  • You have a flat object without pointers, but with an embedded third party structure inside. The third party structure at some point in the future includes a pointer that should not exist twice or more.

So whenever memcopying, keep in mind to check whether pointers could be copied in that specific case, and if that would be okay.

Realise that is_trivially_copyable is only the "Syntax Check", not the "Semantic Test", in compiler parlance.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
7

From http://en.cppreference.com/w/cpp/types/is_trivially_copyable:

Objects of trivially-copyable types are the only C++ objects that may be safely copied with std::memcpy or serialized to/from binary files with std::ofstream::write()/std::ifstream::read(). In general, a trivially copyable type is any type for which the underlying bytes can be copied to an array of char or unsigned char and into a new object of the same type, and the resulting object would have the same value as the original.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
7

Objects with trivial copy constructors, trivial copy assignment operators and trivial destructors can be copied with memcpy or memmove

The requirements for a special member function of a class T to be trivial are

Copy constructors (cc) and copy assignment operators (ca)

  • Not being user-provided (meaning, it is implicitly-defined or defaulted), and if it is defaulted, its signature is the same as implicitly-defined
  • T has no virtual member functions
  • T has no virtual base classes
  • The cc/ca selected for every direct base of T is trivial
  • The cc/ca selected for every non-static class type (or array of class type) memeber of T is trivial
  • T has no non-static data members of volatile-qualified type (since C++14)

Destructors

  • Not being user-provided (meaning, it is implicitly-defined or defaulted)
  • Not being virtual (that is, the base class destructor is not virtual)
  • All direct base classes have trivial destructors
  • All non-static data members of class type (or array of class type) have trivial destructors

Just declaring the function as = default doesn’t make it trivial (it will only be trivial if the class also supports all the other criteria for the corresponding function to be trivial) but explicitly writing the function in user code does prevent it from being trivial. Also all data types compatible with the C language (POD types) are trivially copyable.

Source : C++ Concurrency in action and cppreference.com

Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • 1
    why is a a trivial destructor needed to memcpy something? – Germán Diago Nov 19 '14 at 06:33
  • @GermánDiago Beats me ... just quoting from " C++ Concurrency in action" The rest of the evidence hints thats it's not needed (too bad I can't find a compiler that implements `std::is_trivially_copyable`) – Nikos Athanasiou Nov 19 '14 at 07:04
  • So this means that trivially_destructible is not a requirement, right? That is what you meant? – Germán Diago Nov 19 '14 at 07:16
  • @GermánDiago I tried writing a struct that only implements a destructor (making it non trivial) and in VS12 that implements `std::is_trivially_copyable` I get a negative response. If VS and Antony Williams are right, then it is a requirement and I'm guessing it has to do with the class layout, noexcept guarrantee, C-like behavior and stuff like that. There's no online VS compiler to show this though – Nikos Athanasiou Nov 19 '14 at 07:22
  • If you make your non-default destructor noexcept, works? – Germán Diago Nov 19 '14 at 07:24
  • I made it `throw()` (VS does not implement `noexcept`) and it still gives a `::value=0` – Nikos Athanasiou Nov 19 '14 at 07:25
  • I vote you up then :D Everything seems to be correct. For me it is still a bit of a mistery the default destructor, anyway :(. – Germán Diago Nov 19 '14 at 07:26
  • 2
    @GermánDiago: If the destructor is not trivial then you are not properly destroying the objects that exist at the target location, if any exist (that is, you're not `memcpy`ing into a `char` array to create your new "object"). – Lightness Races in Orbit Nov 19 '14 at 11:37
2

What I understood is

  • An Object should have default constructor /destructor.
  • Default Copy and Move Operations.
  • No static and Virtual Functions has multiple
  • access specifiers for non-static data members prevents important
  • layout optimizations has a non-static member or a base that is not standard layout.

you can test if given type is pod (Plain Old Data) by using standard function is_pod::value

Reference: The C++ programming Language 4th edition

Ali Kazmi
  • 1,460
  • 9
  • 22