Initializing an object to all zeroes

后端 未结 12 632
离开以前
离开以前 2020-12-03 01:27

Oftentimes data structures\' valid initialization is to set all members to zero. Even when programming in C++, one may need to interface with an external API for which this

12条回答
  •  情话喂你
    2020-12-03 02:14

    memset is practically never the right way to do it. And yes, there is a practical difference (see below).

    In C++ not everything can be initialized with literal 0 (objects of enum types can't be), which is why in C++ the common idiom is

    some_struct s = {};
    

    while in C the idiom is

    some_struct s = { 0 };
    

    Note, that in C the = { 0 } is what can be called the universal zero initializer. It can be used with objects of virtually any type, since the {}-enclosed initializers are allowed with scalar objects as well

    int x = { 0 }; /* legal in C (and in C++) */
    

    which makes the = { 0 } useful in generic type-independent C code (type-independent macros for example).

    The drawback of = { 0 } initializer in C89/90 and C++ is that it can only be used as a part of declaration. (C99 fixed this problem by introducing compound literals. Similar functionality is coming to C++ as well.) For this reason you might see many programmers use memset in order to zero something out in the middle of C89/90 or C++ the code. Yet, I'd say that the proper way to do is still without memset but rather with something like

    some_struct s;
    ...
    {
      const some_struct ZERO = { 0 };  
      s = ZERO;
    }
    ...
    

    i.e. by introducing a "fictive" block in the middle of the code, even though it might not look too pretty at the first sight. Of course, in C++ there's no need to introduce a block.

    As for the practical difference... You might hear some people say that memset will produce the same results in practice, since in practice the physical all-zero bit pattern is what is used to represent zero values for all types. However, this is generally not true. An immediate example that would demonstrate the difference in a typical C++ implementation is a pointer-to-data-member type

    struct S;
    ...
    
    int S::*p = { 0 };
    assert(p == NULL); // this assertion is guaranteed to hold
    
    memset(&p, 0, sizeof p);
    assert(p == NULL); // this assertion will normally fail
    

    This happens because a typical implementation usually uses the all-one bit pattern (0xFFFF...) to represent the null pointer of this type. The above example demonstrates a real-life practical difference between a zeroing memset and a normal = { 0 } initializer.

提交回复
热议问题