7

我知道 memset 不赞成class初始化。例如,如下所示:

class X { public: 
X() { memset( this, 0, sizeof(*this) ) ; }
...
} ;

vtbl如果混合中有一个virtual函数, 将会破坏。

我正在开发一个(巨大的)遗留代码库,它是 C-ish 但用 C++ 编译的,所以所有有问题的成员通常都是 POD,不需要传统的 C++ 构造函数。C++ 的使用逐渐普及(就像虚函数一样),这让那些没有意识到 memset 具有这些额外的 C++ 牙齿的开发人员陷入了困境。

我想知道是否有一种 C++ 安全的方法来进行初始的全部零初始化,然后可能是不适合零初始化的特定的成员初始化?

我发现类似的问题memset 用于 C++ 中的初始化,并使用 memset 将派生结构归零。这两个都有“不要使用 memset()”的答案,但没有好的选择(尤其是对于可能包含许多成员的大型结构)。

4

7 回答 7

4

对于找到memset调用的每个类,添加一个memset成员函数,该函数忽略指针和大小参数,并对所有数据成员进行赋值。

编辑: 实际上,它不应该忽略指针,它应该将它与this. 在匹配时,为对象做正确的事情,在不匹配时,重新路由到全局函数。

于 2012-10-15T19:39:38.537 回答
1

You could always add constructors to these embedded structures, so they clear themselves so to speak.

于 2012-10-15T19:34:00.330 回答
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运算符,但这可能会产生负面的性能影响。

编辑:我刚刚意识到这种方法不适用于堆栈分配的对象。

于 2012-10-15T19:38:43.310 回答
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; 
   };
于 2012-10-15T19:42:08.143 回答
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;
}

然而,上述将导致(模板化类的)构造函数被第二次调用。

对于导致没有 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) = {};
    };
};
于 2016-06-29T14:57:00.707 回答
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,然后我意识到您可以直接使用成员地址。)

于 2012-10-15T20:05:37.093 回答
0

我能找到的更好的解决方案是创建一个单独的结构,您将在其中将必须 memsetted 的成员设置为零。不确定这个设计是否适合你。

这个结构没有 vtable 并且没有扩展。这将只是一大块数据。这种方式 memsetting 结构是安全的。

我做了一个例子:

#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;
}
于 2012-10-15T20:57:33.490 回答