用一个非平凡的构造函数初始化一个联合。

时间:2022-09-02 12:11:35

I have a structure which I create a custom constructor to initialize the members to 0's. I've seen in older compilers that when in release mode, without doing a memset to 0, the values are not initialized.

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

I now want to use this structure in a union, but get errors because it has a non-trivial constructor.

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

So, question 1. Does the default compiler implemented constructor guarantee that all members of a structure will be null initialized? The non-trivial constructor just does a memset of all the members to '0' to ensure a clean structure.

所以,问题1。默认编译器实现的构造函数是否保证结构的所有成员都将被初始化?非平凡的构造函数只对所有成员执行一个到'0'的memset,以确保一个干净的结构。

Question 2: If a constructor must be specified on the base structure, how can a union be implemented to contain that element and ensure a 0 initialized base element?

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

6 个解决方案

#1


41  

Question 1: Default constructors do initialize POD members to 0 according to the C++ standard. See the quoted text below.

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

Question 2: If a constructor must be specified in a base class, then that class cannot be part of a union.

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

Finally, you can provide a constructor for your union:

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

union U 
{
   A a;
   B b;

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

For Q1:

Q1:

From C++03, 12.1 Constructors, pg 190

从c++ 03, 12.1构造函数,pg 190

The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body.

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

From C++03, 8.5 Initializers, pg 145

从c++ 03, 8.5初始化器,pg 145

To default-initialize an object of type T means:

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

  • if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • 如果T是一种非pod类类型(第9条),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是病态的);
  • if T is an array type, each element is default-initialized;
  • 如果T是数组类型,则每个元素都是默认初始化的;
  • otherwise, the object is zero-initialized.
  • 否则,对象是零初始化的。

To zero-initialize an object of type T means:

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

  • if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
  • 如果T是标量类型(3.9),则将对象设置为转换为T的0 (0);
  • if T is a non-union class type, each non static data member and each base-class subobject is zero-initialized;
  • 如果T是一个非union类类型,则每个非静态数据成员和每个base类subobject都是零初始化的;
  • if T is a union type, the object’s first named data member is zero-initialized;
  • 如果T是一个联合类型,则对象的第一个命名数据成员为零初始化;
  • if T is an array type, each element is zero-initialized;
  • 如果T是数组类型,则每个元素都是零初始化的;
  • if T is a reference type, no initialization is performed.
  • 如果T是引用类型,则不执行初始化。

For Q2:

Q2:

From C++03, 12.1 Constructors, pg 190

从c++ 03, 12.1构造函数,pg 190

A constructor is trivial if it is an implicitly-declared default constructor and if:

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

  • its class has no virtual functions (10.3) and no virtual base classes (10.1), and
  • 它的类没有虚函数(10.3),也没有虚基类(10.1),并且
  • all the direct base classes of its class have trivial constructors, and
  • 它的类的所有直接基类都有普通的构造函数
  • for all the nonstatic data members of its class that are of class type (or array thereof), each such class has a trivial constructor
  • 对于类类型(或其数组)的类的所有非静态数据成员,每个此类类都有一个普通的构造函数

From C++03, 9.5 Unions, pg 162

从c++ 03, 9.5联盟,第162页

A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class.An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects

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

#2


24  

Things changed for the better in C++11.

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

You can now legally do this, as described by Stroustrup himself (I reached that link from the Wikipedia article on C++11).

您现在可以合法地这样做,就像Stroustrup自己描述的那样(我从Wikipedia关于c++ 11的文章中找到了这个链接)。

The example on Wikipedia is as follows:

*上的例子如下:

#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 goes into a little more detail.

Stroustrup讲得更详细一些。

#3


3  

AFAIK union members may not have constructors or destructors.

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

Question 1: no, there's no such guarantee. Any POD-member not in the constructor's initialization list gets default-initialized, but that's with a constructor you define, and has an initializer list. If you don't define a constructor, or you define a constructor without an initializer list and empty body, POD-members will not be initialized.

问题1:不,没有这样的保证。任何不在构造函数的初始化列表中的pod成员都将被默认初始化,但这是您定义的构造函数,并具有初始化列表。如果没有定义构造函数,或者定义没有初始化器列表和空主体的构造函数,那么pod成员将不会被初始化。

Non-POD members will always be constructed via their default constructor, which if synthesized, again would not initialize POD-members. Given that union members may not have constructors, you'd pretty much be guaranteed that POD-members of structs in a union will not be initialized.

非pod成员将始终通过它们的默认构造函数来构造,如果合成了这些构造函数,也不会初始化pod成员。考虑到union成员可能没有构造函数,您将几乎得到保证,不会初始化union中结构体的POD-members。

Question 2: you can always initialize structures/unions like so:

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

struct foo
{
    int a;
    int b;
};

union bar
{
    int a;
    foo f;
};

bar b = { 0 };

#4


2  

As mentioned in Greg Rogers' comment to unwesen's post, you can give your union a constructor (and destructor if you wish):

正如Greg Rogers对unwesen的文章所提到的那样,您可以给您的union一个构造函数(如果您希望的话,也可以是析构函数):

struct foo
{
    int a;
    int b;
};

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

    int a;
    foo f;
};

#5


0  

Can you do something like this?

你能做这样的事吗?

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

...or maybe something like this?

…或者像这样?

union MyUnion
{
    int qty_;
    double price_;
};

void someFunction()
{
    MyUnion u = {0};
}

#6


-1  

You'll have to wait for C++0x to be supported by compilers to get this. Until then, sorry.

您必须等待c++ 0x得到编译器的支持才能得到这个。在那之前,对不起。

#1


41  

Question 1: Default constructors do initialize POD members to 0 according to the C++ standard. See the quoted text below.

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

Question 2: If a constructor must be specified in a base class, then that class cannot be part of a union.

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

Finally, you can provide a constructor for your union:

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

union U 
{
   A a;
   B b;

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

For Q1:

Q1:

From C++03, 12.1 Constructors, pg 190

从c++ 03, 12.1构造函数,pg 190

The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body.

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

From C++03, 8.5 Initializers, pg 145

从c++ 03, 8.5初始化器,pg 145

To default-initialize an object of type T means:

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

  • if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • 如果T是一种非pod类类型(第9条),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是病态的);
  • if T is an array type, each element is default-initialized;
  • 如果T是数组类型,则每个元素都是默认初始化的;
  • otherwise, the object is zero-initialized.
  • 否则,对象是零初始化的。

To zero-initialize an object of type T means:

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

  • if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
  • 如果T是标量类型(3.9),则将对象设置为转换为T的0 (0);
  • if T is a non-union class type, each non static data member and each base-class subobject is zero-initialized;
  • 如果T是一个非union类类型,则每个非静态数据成员和每个base类subobject都是零初始化的;
  • if T is a union type, the object’s first named data member is zero-initialized;
  • 如果T是一个联合类型,则对象的第一个命名数据成员为零初始化;
  • if T is an array type, each element is zero-initialized;
  • 如果T是数组类型,则每个元素都是零初始化的;
  • if T is a reference type, no initialization is performed.
  • 如果T是引用类型,则不执行初始化。

For Q2:

Q2:

From C++03, 12.1 Constructors, pg 190

从c++ 03, 12.1构造函数,pg 190

A constructor is trivial if it is an implicitly-declared default constructor and if:

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

  • its class has no virtual functions (10.3) and no virtual base classes (10.1), and
  • 它的类没有虚函数(10.3),也没有虚基类(10.1),并且
  • all the direct base classes of its class have trivial constructors, and
  • 它的类的所有直接基类都有普通的构造函数
  • for all the nonstatic data members of its class that are of class type (or array thereof), each such class has a trivial constructor
  • 对于类类型(或其数组)的类的所有非静态数据成员,每个此类类都有一个普通的构造函数

From C++03, 9.5 Unions, pg 162

从c++ 03, 9.5联盟,第162页

A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class.An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects

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

#2


24  

Things changed for the better in C++11.

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

You can now legally do this, as described by Stroustrup himself (I reached that link from the Wikipedia article on C++11).

您现在可以合法地这样做,就像Stroustrup自己描述的那样(我从Wikipedia关于c++ 11的文章中找到了这个链接)。

The example on Wikipedia is as follows:

*上的例子如下:

#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 goes into a little more detail.

Stroustrup讲得更详细一些。

#3


3  

AFAIK union members may not have constructors or destructors.

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

Question 1: no, there's no such guarantee. Any POD-member not in the constructor's initialization list gets default-initialized, but that's with a constructor you define, and has an initializer list. If you don't define a constructor, or you define a constructor without an initializer list and empty body, POD-members will not be initialized.

问题1:不,没有这样的保证。任何不在构造函数的初始化列表中的pod成员都将被默认初始化,但这是您定义的构造函数,并具有初始化列表。如果没有定义构造函数,或者定义没有初始化器列表和空主体的构造函数,那么pod成员将不会被初始化。

Non-POD members will always be constructed via their default constructor, which if synthesized, again would not initialize POD-members. Given that union members may not have constructors, you'd pretty much be guaranteed that POD-members of structs in a union will not be initialized.

非pod成员将始终通过它们的默认构造函数来构造,如果合成了这些构造函数,也不会初始化pod成员。考虑到union成员可能没有构造函数,您将几乎得到保证,不会初始化union中结构体的POD-members。

Question 2: you can always initialize structures/unions like so:

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

struct foo
{
    int a;
    int b;
};

union bar
{
    int a;
    foo f;
};

bar b = { 0 };

#4


2  

As mentioned in Greg Rogers' comment to unwesen's post, you can give your union a constructor (and destructor if you wish):

正如Greg Rogers对unwesen的文章所提到的那样,您可以给您的union一个构造函数(如果您希望的话,也可以是析构函数):

struct foo
{
    int a;
    int b;
};

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

    int a;
    foo f;
};

#5


0  

Can you do something like this?

你能做这样的事吗?

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

...or maybe something like this?

…或者像这样?

union MyUnion
{
    int qty_;
    double price_;
};

void someFunction()
{
    MyUnion u = {0};
}

#6


-1  

You'll have to wait for C++0x to be supported by compilers to get this. Until then, sorry.

您必须等待c++ 0x得到编译器的支持才能得到这个。在那之前,对不起。