使用memset归零派生结构

时间:2011-08-16 17:55:14

标签: c++ constructor sizeof memset

我想将派生结构的所有成员归零。

每隔一段时间就会有数百个成员和更多成员被添加,所以我觉得明确地初始化它们容易出错。

结构没有虚函数,所有成员字段都是内置的。然而,由于拥有非平凡的构造函数,它们不是POD。

除了对练习的标准皱眉外,您是否看到以下任何问题?

struct Base
{
    // Stuff
};

struct Derived : public Base
{
    // Hundreds of fields of different built-in types
    // including arrays

    Derived()
    {
        ::memset(reinterpret_cast<char*>this + sizeof (Base), 0, sizeof *this - sizeof (Base));
    }
};

感谢。

4 个答案:

答案 0 :(得分:9)

这假定Base基类子对象位于Derived的开头。如果添加另一个基类,这将不起作用。

此外,您的代码是错误的:指针算术是根据对象执行的,而不是以字节为单位。您需要使用reinterpret_cast<char*>(this)以字节为单位执行算术运算。无论如何,你仍然不应该这样做。

考虑以下非丑陋的,符合标准的方法,利用值初始化:

struct Derived : public Base
{
    struct DerivedMembers { /* ... */ }

    DerivedMembers data;

    Derived() : data() { }
};

只要DerivedMembers没有构造函数,就会初始化data的每个数据成员,这看起来就像你想要的行为。

或者,如果您希望在不使用“data”成员变量的情况下访问成员,请考虑使用其他基类:

struct DerivedMembers { /* ... */ }

struct Derived : Base, DerivedMembers
{
    Derived() : DerivedMembers() { }
};

答案 1 :(得分:2)

你不应该这样做。您应该在每个类中使用初始化列表,以避免必须执行此操作。在第一遍中完成它将是一项繁忙的工作,但如果在那之后实践被遵循它是微不足道的。

请参阅此similar question

答案 2 :(得分:2)

您应该将所有值显式设置为零,而不使用memset,因为这不可移植。编译器/内存分配可能会存储您可能会覆盖的内务处理数据。

答案 3 :(得分:2)

标准并没有“对实践不屑一顾”;它给出了未定义的行为

例如:

this + sizeof (Base)

C ++标准中没有任何内容表明此表达式解析为指向Derived的指针。实际上,由于this的类型是Derived * const,那么你所做的就是指针算术。 C ++会尝试添加它,好像this是指向Derived数组的指针,相当于this[sizeof(Base)]。这可能不是你想要的。

如果您不确定如何正确行事,请不要走未定义行为的黑暗走廊。

最重要的是,即使你把体操指向实际工作,你的代码也会变得非常脆弱。它可能适用于此版本的编译器,但稍后会失败。做一些简单的事情,例如向Base添加虚拟函数会导致代码中出现 chaos ,因为你会破坏vtable指针。

在我看来,你有几个问题:

  1. 不必要的推导。如果Base中没有虚拟内容,为什么要公开衍生出来呢?
  2. 胖接口。如果你看到一个班级开始有数百的成员,那么它可能做得太多了。