使用 memset 将派生结构清零

发布于 2024-11-30 04:02:32 字数 475 浏览 3 评论 0原文

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

有数百个成员,并且每隔一段时间就会添加更多成员,因此我觉得显式初始化它们很容易出错。

该结构没有虚函数,所有成员字段都是内置的。然而,它们并不是 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));
    }
};

谢谢。

I want to zero out all members of a derived structure.

There are hundreds of members and more are added every once in a while so I feel that initializing them explicitly is error-prone.

The structures have no virtual functions and all the member fields are built-in. However, they are not POD by virtue of having non-trivial constructors.

Apart from the standard frowning on the practice, do you see any issues with the following?

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));
    }
};

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鯉魚旗 2024-12-07 04:02:32

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

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

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

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

    DerivedMembers data;

    Derived() : data() { }
};

只要 DerivedMembers 没有构造函数,这就会对 data 的每个数据成员进行值初始化,看起来这正是您想要的行为。

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

struct DerivedMembers { /* ... */ }

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

This assumes that the Base base class subobject is located at the beginning of Derived. This won't work if you add another base class.

Further, your code is wrong: pointer arithmetic is performed in terms of objects, not in terms of bytes. You need to use reinterpret_cast<char*>(this) to perform the arithmetic in terms of bytes. In any case, you still shouldn't do this.

Consider the following, non-ugly, standards-conforming approach utilizing value initialization:

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

    DerivedMembers data;

    Derived() : data() { }
};

As long as DerivedMembers has no constructor, this will value initialize each of the data members of data, which look like it's exactly the behavior you want.

Or, if you want the members to be accessible without using a "data" member variable, consider using another base class:

struct DerivedMembers { /* ... */ }

struct Derived : Base, DerivedMembers
{
    Derived() : DerivedMembers() { }
};
沒落の蓅哖 2024-12-07 04:02:32

你不应该这样做。您应该在每个类中使用初始化列表,以避免必须这样做。第一次完成它会是很多繁忙的工作,但如果之后继续练习,那就微不足道了。

请参阅此类似问题

You shouldn't do this. You should use initialization lists in each of your classes to avoid the necessity of having to do this. It will be a lot of busy work to get it done on the first pass, but if after that the practice is followed it's trivial.

See this similar question:

盛夏尉蓝 2024-12-07 04:02:32

您应该明确地将所有值设置为零,并且不要使用 memset,因为这不可移植。编译器/内存分配可能存储了您可能会覆盖的内务数据。

You should explicitly set all the values to zero and not use memset as this is not portable. The compiler/memory allocation may have housekeeping data stored that you may be overwriting.

§普罗旺斯的薰衣草 2024-12-07 04:02:32

该标准并不“反对这种做法”;它给出了未定义的行为

例如:

this + sizeof (Base)

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

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

最重要的是,即使您将体操指向实际工作,您的代码也会变得非常脆弱。它可能在您的这个版本的编译器上工作,但在更高版本的编译器上会失败。做一些简单的事情,比如向 Base 添加虚拟函数,将会导致代码混乱,因为您会破坏 vtable 指针。

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

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

The standard does not "frown on the practice"; it gives undefined behavior.

For example:

this + sizeof (Base)

There is nothing in the C++ standard that says that this expression resolves to a pointer to Derived. Indeed, since the type of this is Derived * const, then what you've done is pointer arithmetic. C++ will try to add to it as though this were a pointer to an array of Derived, the equivalent of this[sizeof(Base)]. Which probably isn't what you wanted.

Do not walk the dark corridors of undefined behavior if you're not sure how to do it right.

Most importantly of all, even if you pointer gymnastics to actually work, your code becomes very fragile. It may work on this version of your compiler, but it will fail on a later one. Doing something simple like adding a virtual function to Base will cause chaos in your code, as you will destroy the vtable pointer.

It seems to me that you have a couple of problems:

  1. Needless derivation. If Base has nothing virtual in it, why are you publicly deriving from it?
  2. A fat interface. If you see a class start to have hundreds of members, then it's probably doing too much.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文