c – 不受限制的联合需要放置new和构造函数定义吗?

我看到的无限制工会的例子似乎总是在构建时使用新的位置.*有关C 11特性的文章在联合的构造函数中使用了new.

https://en.wikipedia.org/wiki/C%2B%2B11#Unrestricted_unions

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

是否有必要在这里使用新的位置?例如,这段代码在没有警告的情况下使用gcc进行编译,而valgrind在使用union来保存字符串时没有显示内存泄漏:

struct HasUnresUnion
{
    enum { Int, String } tag;

    HasUnresUnion(int i)
      : tag(Int),
        as_int(i)
    {}

    HasUnresUnion(std::string str)
      : tag(String),
        as_str(std::move(str))
    {}

    ~HasUnresUnion()
    {
        using std::string;
        if (tag == String)
            as_str.~string();
    }

    union
    {
        int as_int;
        std::string as_str;
    };
};

这似乎没有任何歧义,所以我不明白为什么标准会取缔这个.这是合法代码吗?当联合未初始化(而不是被分配)时,是否需要新的位置?是否需要联盟中的构造函数?我确实看到没有自己的构造函数的无限制工会,但*明确表示它是必需的.

解决方法:

介绍

你展示的片段非常安全;在初始化类似联合的类时,法律允许您初始化一个非静态数据成员.

*文章中有一个示例,其中使用了placement-new,因为它们在可以直接初始化某个成员的点之后写入成员.

union A {
   A () { new (&s1) std::string ("hello world"); }
  ~A () { s1.~basic_string<char> (); }
  int         n1;
  std::string s1;
};

然而,前面的代码段在语义上等同于以下内容,其中我们明确声明在构造A时应初始化A :: s1.

union A {
   A () : s1 ("hello world") { }
  ~A () { s1.~basic_string<char> (); }
  int         n1;
  std::string s1;
};

在你的代码片段中,你的类中有一个匿名联合(这使你的类成为一个类似联合的类),这意味着除非你在类的初始化期间初始化union的一个成员 – 你必须使用placement-new来初始化他们以后再来.

标准说什么?

06002

In a union, at most one of the non-static data members can be active at any
time, that is, the value of at most one of the non-static data members can
be stored in a union at any time.

06003

[…]

The lifetime of an object of type T begins when:

  • storage with the proper alignment and size for type T is obtained, and
  • if the object has non-trivial initialization, its initialization is complete.

The lifetime of an object of type T ends when:

  • if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
  • the storage which the object occupies is reused or released.
上一篇:Qt pri文件


下一篇:为什么C禁止匿名结构?