LWG 2424 discusses the undesirable status of atomics, mutexes and condition variables as trivially copyable in C++14. I appreciate that a fix is already lined up, but std::mutex
Either it was my mistake, or I was misquoted, and I honestly don't recall which.
However, I have this very strongly held advice on the subject:
Do not use
is_trivial
noris_trivially_copyable
! EVER!!!
Instead use one of these:
is_trivially_destructible
is_trivially_default_constructible
is_trivially_copy_constructible
is_trivially_copy_assignable
is_trivially_move_constructible
is_trivially_move_assignable
Rationale:
tldr: See this excellent question and correct answer.
No one (including myself) can remember the definition of is_trivial
and is_trivially_copyable
. And if you do happen to look it up, and then spend 10 minutes analyzing it, it may or may not do what you intuitively think it does. And if you manage to analyze it correctly, the CWG may well change its definition with little or no notice and invalidate your code.
Using is_trivial
and is_trivially_copyable
is playing with fire.
However these:
is_trivially_destructible
is_trivially_default_constructible
is_trivially_copy_constructible
is_trivially_copy_assignable
is_trivially_move_constructible
is_trivially_move_assignable
do exactly what they sound like they do, and are not likely to ever have their definition changed. It may seem overly verbose to have to deal with each of the special members individually. But it will pay off in the stability/reliability of your code. And if you must, package these individual traits up into a custom trait.
Update
For example, clang & gcc compile this program:
#include
template
void
test()
{
using namespace std;
static_assert(!is_trivial{}, "");
static_assert( is_trivially_copyable{}, "");
static_assert( is_trivially_destructible{}, "");
static_assert( is_destructible{}, "");
static_assert(!is_trivially_default_constructible{}, "");
static_assert(!is_trivially_copy_constructible{}, "");
static_assert( is_trivially_copy_assignable{}, "");
static_assert(!is_trivially_move_constructible{}, "");
static_assert( is_trivially_move_assignable{}, "");
}
struct X
{
X(const X&) = delete;
};
int
main()
{
test();
}
Note that X
is trivially copyable, but not trivially copy constructible. To the best of my knowledge, this is conforming behavior.
VS-2015 currently says that X
is neither trivially copyable nor trivially copy constructible. I believe this is wrong according to the current spec, but it sure matches what my common sense tells me.
If I needed to memcpy
to uninitialized memory, I would trust is_trivially_copy_constructible
over is_trivially_copyable
to assure me that such an operation would be ok. If I wanted to memcpy
to initialized memory, I would check is_trivially_copy_assignable
.