使用非平凡的构造函数初始化联合

时间:2008-11-26 16:38:47

标签: c++ constructor multiplatform

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

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

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

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

6 个答案:

答案 0 :(得分:46)

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

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

最后,您可以为联盟提供构造函数:

union U 
{
   A a;
   B b;

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

对于Q1:

来自C ++ 03,12.1 Constructors,第190页

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

来自C ++ 03,8.5初始化器,第145页

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

  • 如果T是非POD类类型 (第9节),默认构造函数 因为T被称为(和 如果T,初始化是不正确的 没有可访问的默认值 构造函数);
  • 如果T是数组类型,则每个元素都是默认初始化的;
  • 否则,该对象为零初始化

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

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

第二季度:

来自C ++ 03,12.1 Constructors,第190页

如果构造函数是隐式声明的默认构造函数,并且如果:

,则它是微不足道的
  • 其类没有虚函数(10.3),没有虚基类(10.1)和
  • 其类的所有直接基类都有简单的构造函数和
  • 表示类的所有非静态数据成员(类型数组) 其中,每个这样的类都有一个简单的构造函数

来自C ++ 03,9.5 Unions,第162页

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

答案 1 :(得分:30)

在C ++ 11中,事情变得更好。

您现在可以合法地执行此操作,described by Stroustrup他自己(我从Wikipedia article on C++11到达了该链接。)

维基百科上的例子如下:

#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更详细一点。

答案 2 :(得分:3)

AFAIK工会成员可能没有构造函数或析构函数。

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

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

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

struct foo
{
    int a;
    int b;
};

union bar
{
    int a;
    foo f;
};

bar b = { 0 };

答案 3 :(得分:2)

正如Greg Rogers对unwesen帖子的评论中所提到的,你可以给你的联盟一个构造函数(如果你愿意的话也可以使用析构函数):

struct foo
{
    int a;
    int b;
};

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

    int a;
    foo f;
};

答案 4 :(得分: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};
}

答案 5 :(得分:-1)

您必须等待编译器支持C ++ 0x才能获得此功能。在那之前,抱歉。