我知道memset对class
初始化不满意。例如,类似以下内容:
class X { public:
X() { memset( this, 0, sizeof(*this) ) ; }
...
} ;
如果混合中有vtbl
函数,会破坏virtual
。
我正在开发一个(巨大的)遗留代码库,它是C-ish但是用C ++编译,所以所讨论的所有成员通常都是POD,不需要传统的C ++构造函数。 C ++的使用逐渐深入(就像虚函数一样),这就咬了那些没有意识到memset有这些额外的C ++牙齿的开发人员。
我想知道是否有一种C ++安全的方法来进行初始的全部零初始化,然后可能会进行特定的成员初始化,其中零初始化不合适?
我发现了类似的问题memset for initialization in C++和zeroing derived struct using memset。这两个都有“不使用memset()”的答案,但没有好的选择(特别是对于可能包含许多成员的大型结构)。
答案 0 :(得分:4)
对于找到memset
调用的每个类,添加一个memset
成员函数,该函数忽略指针和大小参数,并为所有数据成员分配。
编辑:
实际上,它不应该忽略指针,它应该将它与this
进行比较。在匹配中,为对象做正确的事情,在不匹配的情况下,重新路由到全局函数。
答案 1 :(得分:1)
你总是可以在这些嵌入式结构中添加构造函数,因此它们可以说清楚了。
答案 2 :(得分:1)
这很可怕,但是你可以重载这些对象(或公共基类)的过载operator new/delete
,并让实现提供零输出缓冲区。像这样:
class HideousBaseClass
{
public:
void* operator new( size_t nSize )
{
void* p = malloc( nSize );
memset( p, 0, nSize );
return p;
}
void operator delete( void* p )
{
if( p )
free( p );
}
};
还可以覆盖全局 new/delete
运算符,但这可能会产生负面影响。
编辑:我刚刚意识到这种方法对堆栈分配的对象不起作用。
答案 3 :(得分:1)
试试这个:
template <class T>
void reset(T& t)
{
t = T();
}
这会将你的对象归零 - 无论它是不是POD。
但不要这样做:
A::A() { reset(*this); }
这将在无限递归中调用A::A
!!!
试试这个:
struct AData { ... all A members };
class A {
public:
A() { reset(data); }
private:
AData data;
};
答案 4 :(得分:1)
利用静态实例初始化为零的事实: https://ideone.com/GEFKG0
template <class T>
struct clearable
{
void clear()
{
static T _clear;
*((T*)this) = _clear;
};
};
class test : public clearable<test>
{
public:
int a;
};
int main()
{
test _test;
_test.a=3;
_test.clear();
printf("%d", _test.a);
return 0;
}
但是上面的内容会导致构造函数(templatised类)被第二次调用。
对于不会导致ctor调用的解决方案,可以使用此代码:https://ideone.com/qTO6ka
template <class T>
struct clearable
{
void *cleared;
clearable():cleared(calloc(sizeof(T), 1)) {}
void clear()
{
*((T*)this) = *((T*)cleared);
};
};
...如果您使用的是C ++ 11,则可以使用以下内容:https://ideone.com/S1ae8G
template <class T>
struct clearable
{
void clear()
{
*((T*)this) = {};
};
};
答案 5 :(得分:0)
您可以使用指针算法查找要清零的字节范围:
class Thing {
public:
Thing() {
memset(&data1, 0, (char*)&lastdata - (char*)&data1 + sizeof(lastdata));
}
private:
int data1;
int data2;
int data3;
// ...
int lastdata;
};
(编辑:我最初使用offsetof()
,但是评论指出这只能用于POD,然后我意识到你可以直接使用成员地址。)
答案 6 :(得分:0)
我能找到的更好的解决方案是创建一个单独的结构,您将把必须被memset的成员放到零。不确定这种设计是否适合您。
这个结构没有vtable并且扩展了nothings。它只是一大块数据。这样设置结构是安全的。
我举了一个例子:
#include <iostream>
#include <cstring>
struct X_c_stuff {
X_c_stuff() {
memset(this,0,sizeof(this));
}
int cMember;
};
class X : private X_c_stuff{
public:
X()
: normalMember(3)
{
std::cout << cMember << normalMember << std::endl;
}
private:
int normalMember;
};
int main() {
X a;
return 0;
}