memset() 或值初始化以将结构归零?
在 Win32 API 编程中,通常使用具有多个字段的 C struct
.通常只有其中几个具有有意义的值,而所有其他值都必须归零.这可以通过以下两种方式之一实现:
In Win32 API programming it's typical to use C struct
s with multiple fields. Usually only a couple of them have meaningful values and all others have to be zeroed out. This can be achieved in either of the two ways:
STRUCT theStruct;
memset( &theStruct, 0, sizeof( STRUCT ) );
或
STRUCT theStruct = {};
第二个变体看起来更简洁――它是单行的,它没有任何可能输入错误并导致植入错误的参数.
The second variant looks cleaner - it's a one-liner, it doesn't have any parameters that could be mistyped and lead to an error being planted.
与第一个变体相比,它有什么缺点吗?使用哪种变体以及为什么?
Does it have any drawbacks compared to the first variant? Which variant to use and why?
推荐答案
这两者的含义非常不同.第一个使用 memset
函数,旨在将内存缓冲区设置为特定值.第二个初始化一个对象.让我用一些代码解释一下:
Those two constructs a very different in their meaning. The first one uses a memset
function, which is intended to set a buffer of memory to certain value. The second to initialize an object. Let me explain it with a bit of code:
假设您有一个结构,其成员仅属于 POD 类型(普通旧数据" - 参见 C++ 中的 POD 类型是什么?)
Lets assume you have a structure that has members only of POD types ("Plain Old Data" - see What are POD types in C++?)
struct POD_OnlyStruct
{
int a;
char b;
};
POD_OnlyStruct t = {}; // OK
POD_OnlyStruct t;
memset(&t, 0, sizeof t); // OK as well
在这种情况下写一个 POD_OnlyStruct t = {}
或 POD_OnlyStruct t;memset(&t, 0, sizeof t)
没有太大区别,因为我们这里唯一的区别是 alignment 字节在 memset
使用.由于您通常无法访问这些字节,因此对您来说没有区别.
In this case writing a POD_OnlyStruct t = {}
or POD_OnlyStruct t; memset(&t, 0, sizeof t)
doesn't make much difference, as the only difference we have here is the alignment bytes being set to zero-value in case of memset
used. Since you don't have access to those bytes normally, there's no difference for you.
另一方面,由于您已将问题标记为 C++,让我们尝试另一个示例,成员类型不同于 POD:
On the other hand, since you've tagged your question as C++, let's try another example, with member types different from POD:
struct TestStruct
{
int a;
std::string b;
};
TestStruct t = {}; // OK
{
TestStruct t1;
memset(&t1, 0, sizeof t1); // ruins member 'b' of our struct
} // Application crashes here
在这种情况下,使用像 TestStruct t = {}
这样的表达式是好的,而在其上使用 memset
会导致崩溃.如果你使用 memset
会发生什么 - 创建了一个 TestStruct
类型的对象,从而创建了一个 std::string
类型的对象,因为它是我们结构的成员.接下来,memset
将对象 b
所在的内存设置为某个值,比如零.现在,一旦我们的 TestStruct 对象超出范围,它将被销毁,当轮到它的成员 std::string b
时,您将看到崩溃,因为该对象的所有内部memset
破坏了结构.
In this case using an expression like TestStruct t = {}
is good, and using a memset
on it will lead to crash. Here's what happens if you use memset
- an object of type TestStruct
is created, thus creating an object of type std::string
, since it's a member of our structure. Next, memset
sets the memory where the object b
was located to certain value, say zero. Now, once our TestStruct object goes out of scope, it is going to be destroyed and when the turn comes to it's member std::string b
you'll see a crash, as all of that object's internal structures were ruined by the memset
.
所以,实际情况是,那些东西非常不同,尽管有时您需要在某些情况下memset
将整个结构归零,但始终很重要的是让确保您了解自己在做什么,并且不会像我们的第二个示例那样犯错误.
So, the reality is, those things are very different, and although you sometimes need to memset
a whole structure to zeroes in certain cases, it's always important to make sure you understand what you're doing, and not make a mistake as in our second example.
我的投票 - 对对象使用memset
仅在需要时,并使用默认初始化x = {}
在所有其他情况下.
My vote - use memset
on objects only if it is required, and use the default initialization x = {}
in all other cases.
相关文章