不受限制的联合是否需要放置新的和构造函数定义?
Do unrestricted unions require placement new and a constructor definition?
我看到的unrestricted union的例子在构造的时候好像总是用placement 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.
};
这里有必要使用placement new吗?例如,这段代码使用 gcc 和 valgrind 编译时没有警告,当联合用于保存字符串时没有显示内存泄漏:
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;
};
};
这里似乎没有任何歧义,所以我不明白为什么标准会禁止这样做。这是法典吗?当联合未初始化(而不是被分配给)时,是否需要放置新的?联合中的构造函数是否需要?我肯定见过没有自己的构造函数的不受限制的联合,但维基百科明确指出它是必需的。
不,这里不需要放置新的。该标准规定,在不受限制的联合的情况下,应显式调用字段构造函数,否则字段将未初始化。
您可以使用传统方式调用构造函数
U(): p() {}
异域风情
U() { new(&p) Point(); }
如果在调用 U
.
的构造函数之前无法构造字段,则第二个变体可能会有用
在这种情况下也不要忘记放置析构函数。
简介
您显示的代码段非常安全;在初始化 类联合 class.
时,法律允许您初始化 one 非静态数据成员
例子
维基百科文章有一个示例,其中使用了 placement-new,因为他们在可以直接初始化某个成员的点之后写入成员。
union A {
A () { new (&s1) std::string ("hello world"); }
~A () { s1.~basic_string<char> (); }
int n1;
std::string s1;
};
然而,前面的片段在语义上等同于以下片段,其中我们明确声明 A::s1
应在构造 A
.
时初始化
union A {
A () : s1 ("hello world") { }
~A () { s1.~basic_string<char> (); }
int n1;
std::string s1;
};
详细说明
在您的代码段中,您的 class 中有一个 匿名联合 (这使您的 class 成为一个 类联合 class),这意味着除非你在 class 的初始化期间初始化 union
的 一个 成员——你必须使用placement-new 稍后初始化它们。
标准怎么说?
9.5/1 -- <b>Unions</b> -- [class.union]p1
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.
3.8/1 -- <b>Object lifetime</b> -- [basic.life]p1
[...]
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.
我看到的unrestricted union的例子在构造的时候好像总是用placement 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.
};
这里有必要使用placement new吗?例如,这段代码使用 gcc 和 valgrind 编译时没有警告,当联合用于保存字符串时没有显示内存泄漏:
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;
};
};
这里似乎没有任何歧义,所以我不明白为什么标准会禁止这样做。这是法典吗?当联合未初始化(而不是被分配给)时,是否需要放置新的?联合中的构造函数是否需要?我肯定见过没有自己的构造函数的不受限制的联合,但维基百科明确指出它是必需的。
不,这里不需要放置新的。该标准规定,在不受限制的联合的情况下,应显式调用字段构造函数,否则字段将未初始化。
您可以使用传统方式调用构造函数
U(): p() {}
异域风情
U() { new(&p) Point(); }
如果在调用 U
.
在这种情况下也不要忘记放置析构函数。
简介
您显示的代码段非常安全;在初始化 类联合 class.
时,法律允许您初始化 one 非静态数据成员例子
维基百科文章有一个示例,其中使用了 placement-new,因为他们在可以直接初始化某个成员的点之后写入成员。
union A {
A () { new (&s1) std::string ("hello world"); }
~A () { s1.~basic_string<char> (); }
int n1;
std::string s1;
};
然而,前面的片段在语义上等同于以下片段,其中我们明确声明 A::s1
应在构造 A
.
union A {
A () : s1 ("hello world") { }
~A () { s1.~basic_string<char> (); }
int n1;
std::string s1;
};
详细说明
在您的代码段中,您的 class 中有一个 匿名联合 (这使您的 class 成为一个 类联合 class),这意味着除非你在 class 的初始化期间初始化 union
的 一个 成员——你必须使用placement-new 稍后初始化它们。
标准怎么说?
9.5/1 -- <b>Unions</b> -- [class.union]p1
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.
3.8/1 -- <b>Object lifetime</b> -- [basic.life]p1
[...]
The lifetime of an object of typeT
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.