C memset似乎没有写给每个成员

Miz*_*zor 6 c++ templates sizeof memset

我写了一个小坐标类来处理int和float坐标.

template <class T>
class vector2
{
public:
    vector2() { memset(this, 0, sizeof(this)); }
    T x;
    T y;
};
Run Code Online (Sandbox Code Playgroud)

然后在main()中我做:

vector2<int> v;
Run Code Online (Sandbox Code Playgroud)

但根据我的MSVC调试器,只有x值设置为0,y值不受影响.我以前从未在模板类中使用sizeof(),这可能是什么导致了麻烦?

dir*_*tly 25

不使用memset- 它从指向的位置开始,将指针的大小(我的x86 Intel机器上的4个字节)清零this.这是一个坏习惯:当使用memset复杂类时,您还将虚拟指针和指向虚拟基础的指针归零.相反:

template <class T>
class vector2
{
public:
    // use initializer lists
    vector2() : x(0), y(0) {}
    T x;
    T y;
};
Run Code Online (Sandbox Code Playgroud)


RBe*_*eig 16

正如其他人所说,memset()这不是正确的方法.然而,有一些微妙之处,为什么不.

首先,您尝试使用memset()的只是清除sizeof(void *)字节.对于您的示例案例,显然恰好是x成员占用的字节数.

简单的解决方法是写入memset(this, 0, sizeof(*this)),在这种情况下将设置xy.

但是,如果您的vector2类具有任何虚方法并且通常的机制用于由编译器表示它们,那么memsetvtable通过将vtable指针设置为NULL 来破坏并破坏实例.这很糟糕.

另一个问题是,如果类型T需要一些构造函数操作比仅将其位设置为0更复杂,则不会调用成员的构造函数,但是通过覆盖成员的内容来破坏它们的效果memset().

唯一正确的操作是将默认构造函数编写为

vector2(): x(0), y(0), {}
Run Code Online (Sandbox Code Playgroud)

并且忘了试着用它memset()来做这件事.

编辑: D.Shawley在评论中指出,对于默认构造函数xy实际上之前的所谓memset()原代码呈现.虽然技术上是正确的,但是调用会memset()覆盖成员,这最好是非常非常糟糕的形式,最坏的情况是调用Undefined Behavior的恶魔.

如上所述,vector2该类是POD,只要类型T也是普通的旧数据,如果Tint或者就是这种情况float.

但是,所有这一切都需要T成为某种bignum价值类别才能导致难以诊断的问题.如果幸运的话,他们会通过解除引用由其创建的NULL指针的访问冲突来尽早表现出来memset().但幸运女神是一个善变的情妇,更可能的结果是一些记忆被泄露,应用程序变得"摇摇欲坠".或者更可能的是,"更加狡猾".

OP在另一个答案的评论中询问"......难道没有办法让memset工作吗?"

答案很简单,"不."

选择C++语言并选择充分利用模板后,您必须通过正确使用语言来支付这些优势.绕过构造函数(在一般情况下)是不正确的.虽然在某些情况下调用memset()C++程序是合法,安全和合理的,但这不是其中之一.


i_a*_*orf 5

问题是这是一个Pointer类型,它是4个字节(在32位系统上),而int是4个字节(在32位系统上).尝试:

sizeof(*this)
Run Code Online (Sandbox Code Playgroud)

编辑:虽然我同意其他人的意见,构造函数中的初始化列表可能是正确的解决方案.