since std::complex is a non-trivial type, compiling the following with GCC 8.1.1
complex<double>* z = new complex<double>[6];
memset(z,0,6*sizeof*z);
delete [] (z);`
produces a warning
clearing an object of non-trivial type
My question is, is there actually any potential harm in doing so?
The behavior of std::memset
is only defined if the pointer it is modifying is a pointer to a TriviallyCopyable type. std::complex
is guaranteed to be a LiteralType, but, as far as I can tell, it isn't guaranteed to be TriviallyCopyable, meaning that std::memset(z, 0, ...)
is not portable.
That said, std::complex
has an array-compatibility guarantee, which states that the storage of a std::complex<T>
is exactly two consecutive T
s and can be reinterpreted as such. This seems to suggest that std::memset
is actually fine, since it would be accessing through this array-oriented access. It may also imply that std::complex<double>
is TriviallyCopyable, but I am unable to determine that.
If you wish to do this, I would suggest being on the safe side and static_assert
ing that std::complex<double>
is TriviallyCopyable:
static_assert(std::is_trivially_copyable<std::complex<double>>::value);
If that assertion holds, then you are guaranteed that the memset
is safe.
In either case, it would be safe to use std::fill
:
std::fill(z, z + 6, std::complex<double>{});
It optimizes down to a call to memset
, albeit with a few more instructions before it. I would recommend using std::fill
unless your benchmarking and profiling showed that those few extra instructions are causing problems.