10

在 C++ 中,我有一个包含匿名位域结构的类。我想将其初始化为零,而不必手动写出所有字段。

我可以想象将初始化放在三个地方:

  1. 在位域中创建构造函数
  2. 在包含类的构造函数的初始化列表中清零
  3. 在包含类的构造函数主体中清零

这个位域有很多字段,我不想一一列举。

例如看下面的代码:

class Big {
    public:
        Big();

        // Bitfield struct
        struct bflag_struct {
            unsigned int field1 : 1;
            unsigned int field2 : 2;
            unsigned int field3 : 1;
            // ...
            unsigned int field20 : 1;
            // bflag_struct(); <--- Here?
        } bflag;

        unsigned int integer_member;
        Big         *pointer_member;
}

Big::Big()
  : bflag(),             // <--- Can I zero bflag here?
    integer_member(0),
    pointer_member(NULL)
{
    // Or here?
}

其中之一更可取吗?还是我还缺少其他东西?

编辑:根据下面接受的答案(由 Ferruccio 提供),我选择了这个解决方案:

class Big {
    // ...

    struct bflag_struct {
        unsigned int field 1 : 1;
        // ...
        bflag_struct() { memset(this, 0, sizeof *this); };
    }

    // ...
}
4

7 回答 7

13

你总是可以在你的构造函数中这样做:

memset(&bflag, 0, sizeof bflag);
于 2009-03-04T20:54:45.713 回答
9

将位域结构与更容易初始化为 0 的东西联合起来。

于 2009-03-04T20:56:33.663 回答
6

您可以使用联合,尽管这会在访问字段时增加额外的间接级别:

class Big {
    union {
        struct {
            unsigned int field1 : 1;
            ...
        } fields;
        unsigned int all_fields;
    };
    ...
};

Big::Big()
  : all_fields(0),
    ...
{
    ...
}

MSVC 允许在联合内部使用匿名结构(参见,例如D3DMATRIXin的定义<d3d9.h>),但这是一个非标准 C++ 扩展,如果可以,您应该避免使用它。

于 2009-03-04T20:56:05.007 回答
2

您使用类似函数的初始化程序(标记为“我可以在这里将 bflag 归零吗?”)100% 足以用 0 值初始化您的 POD 结构。

除非您知道您的编译器在这方面有问题,否则对这些成员进行任何额外的初始化都会将其初始化两次而没有任何好处。

编辑:只是为了“好玩”,我刚刚用 VS2005、VS2008、GCC 3.4.4、GCC 4.2 和 Borland C++ 5.5.1 进行了检查……只有 Borland C++ 5.5.1 弄错了。

我说“错误”是因为在我看来,标准的 8.5 和 8.5.1 暗示类似函数的初始化程序应该对 POD 结构进行零初始化。

于 2009-03-05T15:43:05.690 回答
2

BTW C++20 支持在类定义中初始化位域,例如

class ... {
   int foo : 1 {};
}

使用 -std=c++2a 启用 gcc

于 2019-08-31T22:03:36.620 回答
1

顺便说一句,除非您需要位域来连接一些遗留代码,否则您不应该使用它们。它们本质上是不可移植和低效的。

于 2009-03-04T20:57:07.110 回答
0

您可以在构造函数中使用 ZeroMemory 或 memset 将内存归零,这样看起来更干净。

于 2009-03-04T20:55:07.443 回答