Is this C++ structure initialization trick safe?

前端 未结 16 1185
有刺的猬
有刺的猬 2020-12-23 17:56

Instead of having to remember to initialize a simple \'C\' structure, I might derive from it and zero it in the constructor like this:

struct MY_STRUCT
{
            


        
16条回答
  •  滥情空心
    2020-12-23 18:26

    The examples have "unspecified behaviour".

    For a non-POD, the order by which the compiler lays out an object (all bases classes and members) is unspecified (ISO C++ 10/3). Consider the following:

    struct A {
      int i;
    };
    
    class B : public A {       // 'B' is not a POD
    public:
      B ();
    
    private:
      int j;
    };
    

    This can be laid out as:

    [ int i ][ int j ]
    

    Or as:

    [ int j ][ int i ]
    

    Therefore, using memset directly on the address of 'this' is very much unspecified behaviour. One of the answers above, at first glance looks to be safer:

     memset(static_cast(this), 0, sizeof(MY_STRUCT));
    

    I believe, however, that strictly speaking this too results in unspecified behaviour. I cannot find the normative text, however the note in 10/5 says: "A base class subobject may have a layout (3.7) different from the layout of a most derived object of the same type".

    As a result, I compiler could perform space optimizations with the different members:

    struct A {
      char c1;
    };
    
    struct B {
      char c2;
      char c3;
      char c4;
      int i;
    };
    
    class C : public A, public B
    {
    public:
      C () 
      :  c1 (10);
      {
        memset(static_cast(this), 0, sizeof(B));      
      }
    };
    

    Can be laid out as:

    [ char c1 ] [ char c2, char c3, char c4, int i ]
    

    On a 32 bit system, due to alighments etc. for 'B', sizeof(B) will most likely be 8 bytes. However, sizeof(C) can also be '8' bytes if the compiler packs the data members. Therefore the call to memset might overwrite the value given to 'c1'.

提交回复
热议问题