具有非平凡成员的 C++11 匿名联合

2021-12-30 00:00:00 constructor anonymous c++ c++11 unions

我正在更新我的结构,我想向其中添加一个 std::string 成员.原始结构如下所示:

I'm updating a struct of mine and I was wanting to add a std::string member to it. The original struct looks like this:

struct Value {
  uint64_t lastUpdated;

  union {
    uint64_t ui;
    int64_t i;
    float f;
    bool b;
  };
};

当然,只是向联合添加一个 std::string 成员会导致编译错误,因为通常需要添加对象的非平凡构造函数.对于 std::string(来自informit.com 的文本)

Just adding a std::string member to the union, of course, causes a compile error, because one would normally need to add the non-trivial constructors of the object. In the case of std::string (text from informit.com)

由于 std::string 定义了所有六个特殊成员函数,因此 U 将具有隐式删除的默认构造函数、复制构造函数、复制赋值运算符、移动构造函数、移动赋值运算符和析构函数.实际上,这意味着您无法创建 U 的实例,除非您明确定义了部分或全部特殊成员函数.

Since std::string defines all of the six special member functions, U will have an implicitly deleted default constructor, copy constructor, copy assignment operator, move constructor, move assignment operator and destructor. Effectively, this means that you can't create instances of U unless you define some, or all of the special member functions explicitly.

然后该网站继续提供以下示例代码:

Then the website goes on to give the following sample code:

union U
{
int a;
int b;
string s;
U();
~U();
};

但是,我在结构中使用匿名联合.我在 freenode 上问了 ##C++,他们告诉我正确的方法是将构造函数放在结构中,并给了我这个示例代码:

However, I'm using an anonymous union within a struct. I asked ##C++ on freenode and they told me the correct way to do that was to put the constructor in the struct instead and gave me this example code:

#include <new>

struct Point  {
    Point() {}
    Point(int x, int y): x_(x), y_(y) {}
    int x_, y_;
};

struct Foo
{
  Foo() { new(&p) Point(); }
  union {
    int z;
    double w;
    Point p;
  };
};

int main(void)
{
}

但是从那里我无法弄清楚如何定义 std::string 需要定义的其余特殊函数,而且,我并不完全清楚该示例中的 ctor 是如何工作的.

But from there I can't figure how to make the rest of the special functions that std::string needs defined, and moreover, I'm not entirely clear on how the ctor in that example is working.

我可以找人更清楚地解释一下吗?

Can I get someone to explain this to me a bit clearer?

推荐答案

这里不需要放置 new.

There is no need for placement new here.

Variant 成员不会被编译器生成的构造函数初始化,但是选择一个并使用普通的 ctor-initializer-list 初始化它应该没有问题.在匿名联合中声明的成员实际上是包含类的成员,并且可以在包含类的构造函数中进行初始化.

Variant members won't be initialized by the compiler-generated constructor, but there should be no trouble picking one and initializing it using the normal ctor-initializer-list. Members declared inside anonymous unions are actually members of the containing class, and can be initialized in the containing class's constructor.

此行为在第 9.5 节中描述.[class.union]:

This behavior is described in section 9.5. [class.union]:

类联合 类是联合或具有匿名联合作为直接成员的类.一个类似联合的类 X 有一组 变体成员.如果 X 是一个联合,它的变体成员是非静态数据成员;否则,它的变体成员是作为 X 成员的所有匿名联合的非静态数据成员.

A union-like class is a union or a class that has an anonymous union as a direct member. A union-like class X has a set of variant members. If X is a union its variant members are the non-static data members; otherwise, its variant members are the non-static data members of all anonymous unions that are members of X.

和第 12.6.2 节 [class.base.init]:

and in section 12.6.2 [class.base.init]:

ctor-initializer 可以初始化构造函数类的变体成员.如果 ctor-initializer 为同一个成员或同一个基类指定了多个 mem-initializer,则 ctor-initializer 有问题-形成.

A ctor-initializer may initialize a variant member of the constructor’s class. If a ctor-initializer specifies more than one mem-initializer for the same member or for the same base class, the ctor-initializer is ill-formed.

所以代码可以很简单:

#include <new>

struct Point  {
    Point() {}
    Point(int x, int y): x_(x), y_(y) {}
    int x_, y_;
};

struct Foo
{
  Foo() : p() {} // usual everyday initialization in the ctor-initializer
  union {
    int z;
    double w;
    Point p;
  };
};

int main(void)
{
}

当然,在激活一个变体成员而不是在构造函数中初始化的其他成员时,仍然应该使用placement new.

Of course, placement new should still be used when vivifying a variant member other than the other initialized in the constructor.

相关文章