使用 memset 将派生结构归零
Posted
技术标签:
【中文标题】使用 memset 将派生结构归零【英文标题】:zeroing derived struct using memset 【发布时间】:2011-08-16 17:55:13 【问题描述】:我想将派生结构的所有成员归零。
有数百个成员,并且每隔一段时间就会添加更多成员,所以我觉得显式初始化它们很容易出错。
结构没有虚函数,所有成员字段都是内置的。但是,它们不是 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));
;
谢谢。
【问题讨论】:
【参考方案1】:这假定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()
;
【讨论】:
他不想避免对所有人这样做,因为他说这会“容易出错”吗?我知道没有其他方法可以做到这一点,尽管这是符合标准的,memset
绝对不是解决这个问题的方法。
非常好的工作方式。但是我觉得如果一个类的成员变量太多,那就意味着你需要把这个类分开。
@Seth:这里我们只有一个数据成员data
,这是初始化列表中唯一需要值初始化的数据成员。您可以向DerivedMembers
类添加任意数量的数据成员,它们都将被初始化,而无需在任何初始化代码中提及它们。
@James 他不会收到类似于non-aggregates cannot be initialized with initializer list
的错误,因为他说他的数据有(非平凡的)构造函数吗?
@Seth:OP 说“所有成员字段都是 [of] 内置 [types]”,所以,不,应该没有问题。即使DerivedMembers
有一个类类型的数据成员,也会为该数据成员调用默认构造函数,或者如果它没有用户声明的构造函数,它的数据成员将被值初始化,递归(如果它没有默认值)构造函数,但有其他用户声明的构造函数,OP 的方案首先不起作用,因为他必须在初始化列表中对其进行初始化。【参考方案2】:
你不应该这样做。您应该在每个类中使用初始化列表,以避免必须这样做。第一遍就完成会很忙,但如果之后再继续练习,那就是微不足道的了。
看到这个similar question:
【讨论】:
【参考方案3】:您应该将所有值显式设置为零并且不要使用 memset,因为它不可移植。编译器/内存分配可能存储了您可能正在覆盖的内务管理数据。
【讨论】:
【参考方案4】:标准并没有“对实践不屑一顾”;它给出了未定义的行为。
例如:
this + sizeof (Base)
C++ 标准中没有任何内容表明此表达式解析为指向 Derived 的指针。事实上,既然this
的类型是Derived * const
,那么你所做的就是指针运算。 C++ 将尝试添加它,就好像this
是指向Derived
数组的指针,相当于this[sizeof(Base)]
。这可能不是您想要的。
如果您不确定如何正确行事,请不要走在未定义行为的黑暗走廊中。
最重要的是,即使您将体操指针指向实际工作,您的代码也会变得非常脆弱。它可能适用于您的编译器的这个版本,但它会在以后的版本中失败。做一些简单的事情,比如向Base
添加一个虚函数会在你的代码中造成混乱,因为你会破坏 vtable 指针。
在我看来你有几个问题:
-
不必要的推导。如果
Base
中没有任何虚拟内容,您为什么要公开从它派生?
胖接口。如果您看到一个班级开始有 数百 个成员,那么它可能做得太多了。
【讨论】:
是的,我在编写代码时就意识到了这一点,但不幸的是,在发布到 SO 时忘记了演员阵容。现已修复。以上是关于使用 memset 将派生结构归零的主要内容,如果未能解决你的问题,请参考以下文章