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)),在这种情况下将设置x和y.
但是,如果您的vector2类具有任何虚方法并且通常的机制用于由编译器表示它们,那么memset将vtable通过将vtable指针设置为NULL 来破坏并破坏实例.这很糟糕.
另一个问题是,如果类型T需要一些构造函数操作比仅将其位设置为0更复杂,则不会调用成员的构造函数,但是通过覆盖成员的内容来破坏它们的效果memset().
唯一正确的操作是将默认构造函数编写为
vector2(): x(0), y(0), {}
Run Code Online (Sandbox Code Playgroud)
并且忘了试着用它memset()来做这件事.
编辑: D.Shawley在评论中指出,对于默认构造函数x和y实际上之前的所谓memset()原代码呈现.虽然技术上是正确的,但是调用会memset()覆盖成员,这最好是非常非常糟糕的形式,最坏的情况是调用Undefined Behavior的恶魔.
如上所述,vector2该类是POD,只要类型T也是普通的旧数据,如果T是int或者就是这种情况float.
但是,所有这一切都需要T成为某种bignum价值类别才能导致难以诊断的问题.如果幸运的话,他们会通过解除引用由其创建的NULL指针的访问冲突来尽早表现出来memset().但幸运女神是一个善变的情妇,更可能的结果是一些记忆被泄露,应用程序变得"摇摇欲坠".或者更可能的是,"更加狡猾".
OP在另一个答案的评论中询问"......难道没有办法让memset工作吗?"
答案很简单,"不."
选择C++语言并选择充分利用模板后,您必须通过正确使用语言来支付这些优势.绕过构造函数(在一般情况下)是不正确的.虽然在某些情况下调用memset()C++程序是合法,安全和合理的,但这不是其中之一.
问题是这是一个Pointer类型,它是4个字节(在32位系统上),而int是4个字节(在32位系统上).尝试:
sizeof(*this)
Run Code Online (Sandbox Code Playgroud)
编辑:虽然我同意其他人的意见,构造函数中的初始化列表可能是正确的解决方案.