60

我有一个结构,我创建了一个自定义构造函数来将成员初始化为 0。我在较旧的编译器中看到,在发布模式下,如果不将 memset 设置为 0,则不会初始化这些值。

我现在想在联合中使用这个结构,但是因为它有一个非平凡的构造函数而出错。

那么,问题 1。默认编译器实现的构造函数是否保证结构的所有成员都将被初始化为空?非平凡的构造函数只是将所有成员的 memset 设置为 '0' 以确保结构清晰。

问题 2:如果必须在基础结构上指定构造函数,如何实现联合以包含该元素并确保初始化为 0 的基础元素?

4

6 回答 6

52

问题 1:默认构造函数确实根据 C++ 标准将 POD 成员初始化为 0。请参阅下面的引用文本。

问题 2:如果必须在基类中指定构造函数,则该类不能是联合的一部分。

最后,您可以为您的联合提供一个构造函数:

union U 
{
   A a;
   B b;

   U() { memset( this, 0, sizeof( U ) ); }
};

对于第一季度:

来自 C++03,12.1 构造函数,第 190 页

隐式定义的默认构造函数执行类的一组初始化,这些初始化将由用户编写的具有空 mem-initializer-list (12.6.2) 和空函数体的类的默认构造函数执行。

来自 C++03, 8.5 Initializers, pg 145

默认初始化 T 类型的对象意味着:

  • 如果 T 是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);
  • 如果 T 是数组类型,则每个元素都是默认初始化的;
  • 否则,对象是零初始化的

对 T 类型的对象进行零初始化意味着:

  • 如果 T 是标量类型(3.9),则将对象设置为值 0(零)转换为 T;
  • 如果 T 是非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的
  • 如果 T 是联合类型,则对象的第一个命名数据成员为零初始化;
  • 如果 T 是数组类型,则每个元素都初始化为零;
  • 如果 T 是引用类型,则不执行初始化。

对于第二季度:

来自 C++03,12.1 构造函数,第 190 页

如果构造函数是隐式声明的默认构造函数并且满足以下条件,则构造函数是微不足道的:

  • 它的类没有虚函数 (10.3) 和虚基类 (10.1),并且
  • 其类的所有直接基类都有普通的构造函数,并且
  • 对于其类的所有属于类类型(或其数组)的非静态数据成员,每个这样的类都有一个简单的构造函数

来自 C++03,9.5 联合,第 162 页

联合可以具有成员函数(包括构造函数和析构函数),但不能具有虚拟 (10.3) 函数。联合不应有基类。联合不应用作基类。具有非平凡构造函数 (12.1)、非平凡复制构造函数 (12.8)、非平凡析构函数 (12.4) 或非平凡的类的对象复制赋值运算符(13.5.3、12.8)不能是联合的成员,也不能是此类对象的数组

于 2008-11-26T19:33:20.370 回答
38

在 C++11 中情况变得更好了。

正如Stroustrup本人所描述的那样,您现在可以合法地执行此操作(我从C++11 的 Wikipedia 文章中获得了该链接)。

维基百科上的例子如下:

#include <new> // Required for placement 'new'.

struct Point {
    Point() {}
    Point(int x, int y): x_(x), y_(y) {}
    int x_, y_;
};

union U {
    int z;
    double w;
    Point p; // Illegal in C++03; legal in C++11.
    U() {new(&p) Point();} // Due to the Point member, a constructor
                           // definition is now *required*.
};

Stroustrup 更详细地介绍了一些细节。

于 2015-10-22T20:20:28.070 回答
2

AFAIK 联合成员可能没有构造函数或析构函数。

问题1:不,没有这样的保证。任何不在构造函数初始化列表中的 POD 成员都会被默认初始化,但这是使用您定义的构造函数,并且有一个初始化列表。如果你没有定义构造函数,或者你定义了一个没有初始化列表和空体的构造函数,POD 成员将不会被初始化。

非 POD 成员将始终通过其默认构造函数构造,如果合成,则不会再次初始化 POD 成员。鉴于联合成员可能没有构造函数,您几乎可以保证联合中结构的 POD 成员不会被初始化。

问题 2:您始终可以像这样初始化结构/联合:

struct foo
{
    int a;
    int b;
};

union bar
{
    int a;
    foo f;
};

bar b = { 0 };
于 2008-11-26T17:13:50.370 回答
2

正如 Greg Rogers 对unwesen帖子的评论中提到的,您可以为您的联合提供一个构造函数(如果您愿意,还可以提供析构函数):

struct foo
{
    int a;
    int b;
};

union bar
{
    bar() { memset(this, 0, sizeof(*this)); }

    int a;
    foo f;
};
于 2008-11-26T19:41:16.843 回答
0

你能做这样的事情吗?

class Outer
{
public:
    Outer()
    {
        memset(&inner_, 0, sizeof(inner_));
    }
private:
    union Inner
    {
        int qty_;
        double price_;
    } inner_;
};

...或者可能是这样的?

union MyUnion
{
    int qty_;
    double price_;
};

void someFunction()
{
    MyUnion u = {0};
}
于 2008-11-26T16:44:37.747 回答
-3

您必须等待编译器支持 C++0x 才能获得此功能。到那时,对不起。

于 2008-11-26T17:51:40.497 回答