memset 和 std::complex<double> 的动态数组

memset and a dynamic array of std::complex<double>

因为 std::complex 是一个非常重要的类型,使用 GCC 8.1.1 编译以下内容

complex<double>* z = new complex<double>[6];
memset(z,0,6*sizeof*z);
delete [] (z);`

产生警告

clearing an object of non-trivial type

我的问题是,这样做真的有任何潜在的危害吗?

从不,从不,从不 memset 非 POD 类型。他们有构造函数 是有原因的 。仅仅在它们上面写一堆字节是极不可能给出期望的结果的(如果是这样,类型本身设计得很糟糕,因为它们显然应该首先是 POD - 或者你只是不走运未定义的行为 似乎在 这种 情况下工作 - 在更改优化级别、编译器或平台(或 moon)相)).

只是不要这样做。

std::memset is only defined if the pointer it is modifying is a pointer to a TriviallyCopyable type. std::complex 的行为保证是 LiteralType,但据我所知,它不能保证是 TriviallyCopyable,意思是std::memset(z, 0, ...)不可移植

就是说,std::complex 有一个 array-compatibility guarantee,它表示 std::complex<T> 的存储恰好是两个连续的 T,并且可以这样重新解释。这似乎表明 std::memset 实际上很好,因为它将通过这种面向数组的访问进行访问。这也可能意味着 std::complex<double> TriviallyCopyable,但我无法确定。

如果您想这样做,我建议您安全起见,static_assert认为 std::complex<double>TriviallyCopyable:

static_assert(std::is_trivially_copyable<std::complex<double>>::value);

如果该断言成立,那么可以保证 memset 是安全的。


无论哪种情况,使用 std::fill:

都是安全的
std::fill(z, z + 6, std::complex<double>{});

optimizes down 调用 memset,尽管在它之前还有一些指令。我建议使用 std::fill,除非您的基准测试和分析表明那几条额外的指令导致了问题。

这个问题的答案是,对于符合标准的 std::complexnew 之后不需要 memset

new complex<double>[6] 会将复数初始化为 (0, 0) 因为它调用默认(非平凡)构造函数初始化为零。 (不幸的是,我认为这是一个错误。) https://en.cppreference.com/w/cpp/numeric/complex/complex

如果发布的代码只是 newmemset 之间缺少代码的示例,那么 std::fill 会做正确的事情。 (部分原因是特定的标准库实现在内部知道 std::complex 是如何实现的。)