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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/321351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:37:36  来源:igfitidea点击:

Initializing a union with a non-trivial constructor

c++constructormultiplatform

提问by Superpolock

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。默认编译器实现的构造函数是否保证结构的所有成员都将被初始化为空?非平凡的构造函数只是将所有成员的 memset 设置为 '0' 以确保结构清晰。

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 的基元素?

采纳答案by David Rodríguez - dribeas

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:

对于第一季度:

From C++03, 12.1 Constructors, pg 190

来自 C++03,12.1 构造函数,第 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 初始化程序,第 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);
  • if T is an array type, each element is default-initialized;
  • otherwise, the object is zero-initialized.
  • 如果 T 是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化为病态);
  • 如果 T 是数组类型,则每个元素都是默认初始化的;
  • 否则,对象是零初始化的

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

For Q2:

对于 Q2:

From C++03, 12.1 Constructors, pg 190

来自 C++03,12.1 构造函数,第 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
  • 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
  • 它的类没有虚函数(10.3)和虚基类(10.1),并且
  • 它的类的所有直接基类都有简单的构造函数,并且
  • 对于所有属于类类型(或其数组)的类的非静态数据成员,每个这样的类都有一个简单的构造函数

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) 不能是联合的成员,此类对象的数组也不能

回答by dan-man

Things changed for the better in C++11.

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

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

您现在可以合法地执行此操作,正如Stroustrup本人所描述的那样(我从维基百科关于 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 详细介绍了一点。

回答by dan-man

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 成员。鉴于联合成员可能没有构造函数,您几乎可以保证联合中结构的 POD 成员不会被初始化。

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

回答by Adam Rosenfield

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帖子的评论中提到的,您可以为您的联合提供一个构造函数(如果您愿意,也可以使用析构函数):

struct foo
{
    int a;
    int b;
};

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

    int a;
    foo f;
};

回答by John Dibling

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

回答by Michel

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

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