2
votes

Consider the following code. It can be compiled with both Clang and GCC. However, GCC issues a warning:

warning: 'void* memcpy(void*, const void*, size_t)' writing to an object of non-trivially copyable type 'struct Value'; use copy-assignment or copy-initialization instead [-Wclass-memaccess]

#include <cstring>
#include <iostream>
#include <type_traits>

static unsigned cnt2 = 0;

struct Value {
  Value(int v) noexcept : v(v), m(v+1) { }
 ~Value()      noexcept { cnt2++; }
  int v; 
  int m; 
};

static_assert(std::is_trivially_copy_assignable_v<Value>);

void copy(Value* dst, Value const* src, std::size_t len) {
  std::memcpy(dst,src,sizeof(Value)*len); }

int main() { std::cout << "Hello\n"; }

There are at least two problems here.

  1. Both compilers pass std::is_trivially_copy_assignable_v<Value>. So what is the difference between trivially copy assignable and trivially copyable types?
  2. I think the warning is correct. Because destructor of Value is non-trivial. So does this mean that to use std::memcpy we have to check both std::is_trivially_copy_assignable_v<Value> and std::is_trivially_destructible_v<Value>?
1

1 Answers

1
votes

Both compilers pass std::is_trivially_copy_assignable_v<Value>. So what is the difference between trivially copy assignable and trivially copyable types?

Trivially-copy-assignable requires just operations involving copy-assignment to be trivial. You can have a trivially-copy-assignable class with, for example, a non-trivial destructor or move constructor. Such a class won't be trivially-copyable.

I think the warning is correct. Because destructor of Value is non-trivial. So does this mean that to use std::memcpy we have to check both std::is_trivially_copy_assignable_v<Value> and std::is_trivially_destructible_v<Value>?

I believe you only need to check std::is_trivially_copyable_v<Value>. Both your checks don't give you the required guarantee, since your class can still can have, for example, a non-trivial move constructor and, therefore, will not be trivially-copyable, and, therefore, will not be usable with memcpy.