Is this C++ structure initialization trick safe?

前端 未结 16 1072
有刺的猬
有刺的猬 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:37

    Precise layout of a class or structure is not guaranteed in C++, which is why you should not make assumptions about the size of it from the outside (that means if you're not a compiler).

    Probably it works, until you find a compiler on which it doesn't, or you throw some vtable into the mix.

    0 讨论(0)
  • 2020-12-23 18:41

    This would make me feel much safer as it should work even if there is a vtable (or the compiler will scream).

    memset(static_cast<MY_STRUCT*>(this), 0, sizeof(MY_STRUCT));
    

    I'm sure your solution will work, but I doubt there are any guarantees to be made when mixing memset and classes.

    0 讨论(0)
  • 2020-12-23 18:41

    Try this - overload new.

    EDIT: I should add - This is safe because the memory is zeroed before any constructors are called. Big flaw - only works if object is dynamically allocated.

    struct MY_STRUCT
    {
        int n1;
        int n2;
    };
    
    class CMyStruct : public MY_STRUCT
    {
    public:
        CMyStruct()
        {
            // whatever
        }
        void* new(size_t size)
        {
            // dangerous
            return memset(malloc(size),0,size);
            // better
            if (void *p = malloc(size))
            {
                return (memset(p, 0, size));
            }
            else
            {
                throw bad_alloc();
            }
        }
        void delete(void *p, size_t size)
        {
            free(p);
        }
    
    };
    
    0 讨论(0)
  • 2020-12-23 18:43

    It's a bit of code, but it's reusable; include it once and it should work for any POD. You can pass an instance of this class to any function expecting a MY_STRUCT, or use the GetPointer function to pass it into a function that will modify the structure.

    template <typename STR>
    class CStructWrapper
    {
    private:
        STR MyStruct;
    
    public:
        CStructWrapper() { STR temp = {}; MyStruct = temp;}
        CStructWrapper(const STR &myStruct) : MyStruct(myStruct) {}
    
        operator STR &() { return MyStruct; }
        operator const STR &() const { return MyStruct; }
    
        STR *GetPointer() { return &MyStruct; }
    };
    
    CStructWrapper<MY_STRUCT> myStruct;
    CStructWrapper<ANOTHER_STRUCT> anotherStruct;
    

    This way, you don't have to worry about whether NULLs are all 0, or floating point representations. As long as STR is a simple aggregate type, things will work. When STR is not a simple aggregate type, you'll get a compile-time error, so you won't have to worry about accidentally misusing this. Also, if the type contains something more complex, as long as it has a default constructor, you're ok:

    struct MY_STRUCT2
    {
        int n1;
        std::string s1;
    };
    
    CStructWrapper<MY_STRUCT2> myStruct2; // n1 is set to 0, s1 is set to "";
    

    On the downside, it's slower since you're making an extra temporary copy, and the compiler will assign each member to 0 individually, instead of one memset.

    0 讨论(0)
提交回复
热议问题