构造函数中使用memset初始化this?
面试官:如果我想将一个类的成员变量都初始化为0,那么在构造函数中使用memset(this, 0, sizeof(T))
是否可行?
我:…不知道
那么是否可行呢?我们来尝试一下
#include <iostream>
struct A
{
A() = default;
int a;
char b;
};
class T
{
public:
T()
{
memset(this, 0, sizeof(T));
}
~T() = default;
int geti() const { return i; }
const A& getA() const { return a; }
private:
int i;
A a;
};
int main()
{
T t;
std::cout << t.geti() << std::endl;
std::cout << t.getA().a << std::endl;
std::cout << t.getA().b << std::endl;
return 0;
}
输出结果为:
貌似 没有什么问题?i确实被清为0了,a和b也都被清为0了。
我们知道memset所清的是栈的数据,而这个类的成员函数刚好也都在栈上,所以是没有问题的。
但当存在成员变量申请了堆上的内存,那么使用memset来清0,就会造成内存泄露。
我们简单地修改一下上面的程序:class T没有发生改变,将struct A中的b改为指针,并在构造时从堆上申请一个数组的内存。
#include <iostream>
struct A
{
A()
{
b = new char[10]();
}
int a;
char* b;
};
class T
{
public:
T()
{
memset(this, 0, sizeof(T));
}
~T() = default;
int geti() const { return i; }
const A& getA() const { return a; }
private:
int i;
A a;
};
int main()
{
T t;
std::cout << t.geti() << std::endl;
std::cout << t.getA().a << std::endl;
std::cout << t.getA().b << std::endl;
return 0;
}
执行memset之前:
执行memset之后:
由调试情况可知,执行memset时不会出现任何问题,成员变量a确实被清0了,但问题也在这里出现,我们会发现成员对象a中的指针b在执行memset之前指向一个地址,执行后被置为NULL了,这就导致在构造a时申请的数组不见了,我们就没办法析构new操作申请的数组,就造成了内存的泄露。
所以在构造函数中使用memset来初始化this是比较危险的,有可能会带来内存泄露,不建议这么使用。