C memset seems to not write to every member

后端 未结 7 2129
感动是毒
感动是毒 2021-01-18 09:01

I wrote a small coordinate class to handle both int and float coordinates.

template 
class vector2
{
public:
    vector2() { memset(this, 0, s         


        
7条回答
  •  臣服心动
    2021-01-18 09:12

    As others are saying, memset() is not the right way to do this. There are some subtleties, however, about why not.

    First, your attempt to use memset() is only clearing sizeof(void *) bytes. For your sample case, that apparently is coincidentally the bytes occupied by the x member.

    The simple fix would be to write memset(this, 0, sizeof(*this)), which in this case would set both x and y.

    However, if your vector2 class has any virtual methods and the usual mechanism is used to represent them by your compiler, then that memset will destroy the vtable and break the instance by setting the vtable pointer to NULL. Which is bad.

    Another problem is that if the type T requires some constructor action more complex than just settings its bits to 0, then the constructors for the members are not called, but their effect is ruined by overwriting the content of the members with memset().

    The only correct action is to write your default constructor as

    vector2(): x(0), y(0), {}
    

    and to just forget about trying to use memset() for this at all.

    Edit: D.Shawley pointed out in a comment that the default constructors for x and y were actually called before the memset() in the original code as presented. While technically true, calling memset() overwrites the members, which is at best really, really bad form, and at worst invokes the demons of Undefined Behavior.

    As written, the vector2 class is POD, as long as the type T is also plain old data as would be the case if T were int or float.

    However, all it would take is for T to be some sort of bignum value class to cause problems that could be really hard to diagnose. If you were lucky, they would manifest early through access violations from dereferencing the NULL pointers created by memset(). But Lady Luck is a fickle mistress, and the more likely outcome is that some memory is leaked, and the application gets "shaky". Or more likely, "shakier".

    The OP asked in a comment on another answer "...Isn't there a way to make memset work?"

    The answer there is simply, "No."

    Having chosen the C++ language, and chosen to take full advantage of templates, you have to pay for those advantages by using the language correctly. It simply isn't correct to bypass the constructor (in the general case). While there are circumstances under which it is legal, safe, and sensible to call memset() in a C++ program, this just isn't one of them.

提交回复
热议问题