[英]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.如果发布的代码只是在
new
和memset
之间缺少代码的示例,那么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.