简体   繁体   English

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

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

since std::complex is a non-trivial type, compiling the following with GCC 8.1.1由于 std::complex 是一个非平凡的类型,因此使用 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::memset的行为仅在它正在修改的指针是指向TriviallyCopyable类型的指针时才定义。 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. std::complex保证是LiteralType ,但据我所知,它不能保证是TriviallyCopyable ,这意味着std::memset(z, 0, ...)不可移植。

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.也就是说, std::complex有一个数组兼容性保证,它指出std::complex<T>的存储正好是两个连续的T并且可以这样重新解释。 This seems to suggest that std::memset is actually fine, since it would be accessing through this array-oriented access.这似乎表明std::memset实际上很好,因为它将通过这种面向数组的访问进行访问。 It may also imply that std::complex<double> is TriviallyCopyable , but I am unable to determine that.这也可能意味着std::complex<double>TriviallyCopyable ,但我无法确定。

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 ing std::complex<double>TriviallyCopyable

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

If that assertion holds, then you are guaranteed that the memset is safe.如果该断言成立,则可以保证memset是安全的。


In either case, it would be safe to use std::fill :在任何一种情况下,使用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.优化到调用memset ,尽管在它之前还有一些指令。 I would recommend using std::fill unless your benchmarking and profiling showed that those few extra instructions are causing problems.我建议使用std::fill除非您的基准测试和分析表明那些额外的指令会导致问题。

Never, never, ever memset non-POD types.永远,永远,永远不要memset非 POD 类型。 They have constructors for a reason .他们有构造函数是有原因的 Just writing a bunch of bytes on top of them is highly unlikely to give the desired result (and if it does, the types themselves are badly designed as they should clearly then just be POD in the first place - or you are simply being unlucky that Undefined Behaviour seems to work in this case - have fun debugging it when it doesn't after you change optimization level, compiler or platform (or moon phase)).仅仅在它们上面写一堆字节不太可能给出想要的结果(如果确实如此,类型本身设计得很糟糕,因为它们应该清楚地然后只是首先成为 POD - 或者你只是不走运在这种情况下,未定义的行为似乎有效- 在您更改优化级别、编译器或平台(或月相)后没有出现时,调试它很有趣。

Just don't do this.不要这样做。

The answer to this question is that for a standard-compliant std::complex there is no need for memset after new .这个问题的答案是,对于符合std::complex ,在new之后不需要memset

new complex<double>[6] will initialize the complex to (0, 0) because it calls a default (non-trivial) constructor that initializes to zero. new complex<double>[6]会将复合体初始化为(0, 0)因为它调用初始化为零的默认(非平凡)构造函数。 (I think this is a mistake unfortunately.) https://en.cppreference.com/w/cpp/numeric/complex/complex (不幸的是,我认为这是一个错误。) https://en.cppreference.com/w/cpp/numeric/complex/complex

If the code posted was just and example with missing code between new and memset , then std::fill will do the right thing.如果发布的代码只是在newmemset之间缺少代码的示例,那么std::fill将做正确的事情。 (In part because the specific standard library implementation knows internally how std::complex is implemented.) (部分是因为特定的标准库实现在内部知道std::complex是如何实现的。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM