为什么匿名联合不能包含具有重要构造函数/析构函数的成员?

发布于 2024-10-06 15:23:14 字数 612 浏览 2 评论 0原文

我可能是错的,但我发现的基本解释是联合无法初始化,因为它不知道要调用哪个成员的构造函数。编译器无法自动生成联合的构造函数。

为什么不允许用户定义 union 构造函数?这将消除上述问题并允许具有重要构造函数/析构函数的工会成员的存在。

另外,为什么联合成员不能有任何自定义构造函数?前面的解释并不代表自定义构造函数。

更新 1:

示例:

struct SQuaternion
{
    union
    {
        S3DVector Axis;
        struct
        {
            float X;
            float Y;
            float Z;
        };
    };
    float W;
};

注意:这里的问题似乎是工会是匿名的。因此,如何命名联合的构造函数?这样做似乎是不可能的,仅仅因为它没有名字,没有其他原因。如果这是一个简单的词汇问题,那将是一个可怕的原因......

更新2: 只需将有问题的成员包装在封闭的匿名结构中,错误就会消失。我认为这是匿名工会所能做的最接近的事情。它不再是一个问题的事实仍然看起来很奇怪......

I may be mistaken, but the basic explanation I've found has been that the union can't initialize because it doesn't know which member's constructor to call. The compiler can not automatically generate a constructor for the union.

Why is the user not allowed to define the unions constructor? This would remove said issue and allow the presence of union members that have a non-trivial constructor/destructor.

Also, why can't a union member have any custom constructors? The previous explanation doesn't stand for custom constructors.

Update 1:

Example:

struct SQuaternion
{
    union
    {
        S3DVector Axis;
        struct
        {
            float X;
            float Y;
            float Z;
        };
    };
    float W;
};

Note: The issue here seems to be that the union is anonymous. As such, how would one name the constructor of the union? It seems impossible to do so, merely because it has no name, and for no other reason. It'd be a terrible reason if it was a simple lexical issue...

Update 2:
Simply by wrapping the offending member in an enclosing anonymous structure, the error disappears. I suppose this is the closest thing one can do with an anonymous union. The fact that it ceases to be an issue still seems strange...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

菊凝晚露 2024-10-13 15:23:14

更大的原因是:联合体如何知道要调用哪个析构函数。该语言本身并不跟踪哪个成员在联盟中处于活跃状态。

似乎 C++0x 将允许联合中使用非平凡类型,在这种情况下,您将被迫实现自己的构造函数和析构函数。 (后者从 提案中有点不清楚< /a>,似乎联合析构函数不会调用任何成员析构函数,并且必须手动调用正确的析构函数。)

A bigger reason would be: how would the union know which destructor to call. The language itself doesn't track which member is active in a union.

It seems that C++0x will allow non-trivial types in unions, in which case you'll be forced to implement your own constructor(s) and destructor. (The latter is a little unclear from the proposal, it seems that the union destructor will not call any member destructors and the destructor for the right one would have to be invoked manually.)

半衾梦 2024-10-13 15:23:14

定义这样的东西也许是可能的,但这会带来一堆蠕虫,几乎肯定不值得:

  1. 构造哪个对象?
  2. 如果定义联合构造函数,它如何构造一个对象与另一个对象?
  3. 是否必须为每个非 Pod 成员定义一个构造函数?
  4. 分配给与当前分配的对象不同的对象的语法是什么?
  5. 您是否允许一个对象在另一个对象的上下文中进行解释?目前联合体允许这种情况,并且是一种非常常见的用例(union { char c[4]; int n; } u; un=1234; cout << uc [1];)。
  6. 编译器如何知道要调用哪个析构函数?
  7. 编译器如何知道复制联合时要调用哪个复制构造函数?

(我遗漏了什么吗?)

我怀疑它只是进了太硬的篮子。

It probably would be possible to define such a thing, but that would open such a can of worms that it almost certainly wouldn't be worth it:

  1. Which object to construct?
  2. If you define a union constructor, how does it construct one object vs another?
  3. Do you have to define one constructor per non-pod member?
  4. What is the syntax for assigning to a different object to the one that is currently assigned?
  5. Do you allow one object to be interpreted in the context of another? This is allowed for unions currently, and is a very common use-case (union { char c[4]; int n; } u; u.n=1234; cout << u.c[1];).
  6. How does the compiler know which destructor to call?
  7. How does the compiler know which copy-constructor to call when copying a union?

(Have I left anything out?)

I suspect it just went into the too-hard basket.

青萝楚歌 2024-10-13 15:23:14

我认为你是对的,C++ 中的联合功能不足。它们几乎是 C 联合体的直接副本,这意味着它们不充当 C++ 的变体类型

C++ 中的 union 没有简单的方法来表示正确的变体类型。考虑以下代码(如果它是合法的):

union X {
    int i;
    std::string s;
};

X x;
x.s = "Hello";
x.i = 23;

X 的构造函数或析构函数的数量无法确保最后一行中的赋值在存储 23 之前调用 ~string。为了让编译器做到这一点,联合必须包含某种指示符存储什么类型。这就是为什么一切都必须是 POD 的原因。我不知道命名联合和未命名联合之间存在差异的原因,但这对两者都适用。

如果 C++ 联合体的所有成员都是 POD,那么也许 C++ 联合体可以被定义为类似于 C 联合体,但要包含这些额外信息,并在正确的时间调用正确的析构函数(如果任何成员是非 POD) 。但这不是您提议的简单改变。

您可以通过编写一个类来编写变体类型,该类具有一个值来指示当前存储的类型,然后是构造函数、复制赋值运算符和析构函数,如果您被允许的话,您可以将它们放入联合中。

使用 char 数组进行存储,使用 new 进行构造/赋值,并在析构函数中直接调用正确的析构函数。

请注意对齐问题 - 您需要确保原始存储对于您放置在其中的任何类型都充分对齐。实现此目的的一种方法是动态分配它。另一种方法是将您的 char 数组与任何具有最大对齐要求的内置类型(如果您不知道:所有这些)放入联合中。

与您想要的联合在用法上唯一不同的是,它不是公共数据成员 int afloat bstring c ,您必须提供返回代理对象(可能是对对象本身的引用)的访问器,该访问器能够正确分配,这意味着首先调用旧类型的析构函数。然后您可以编写 xi() = 23 而不是 xi = 23

或者,您可以使用 Boost.Variant

I think you're right, unions in C++ are under-featured. They're pretty much a straight copy of unions from C, which means that they don't serve as variant types for C++.

There's no simple way for union in C++ to represent a proper variant type. Consider the following code, if it were legal:

union X {
    int i;
    std::string s;
};

X x;
x.s = "Hello";
x.i = 23;

No amount of constructors or destructors for X is going to ensure that the assignment in the final line calls ~string before storing 23. For the compiler to do it, the union would have to contain some kind of indicator what type is stored. That's why everything must be POD. I don't know the reasons for the differences between named and unnamed unions, though, this applies to both.

Perhaps C++ unions could have been defined to be like C unions if all their members are POD, but to contain this extra information, and call the correct destructors at the correct times, if any member is non-POD. But this isn't the simple change you proposed.

You can somewhat laboriously write a variant type by writing a class which has a value to indicate the type currently stored, and then the constructors, copy assignment operator, and destructor that you would have put in your union, had you been allowed.

Use a char array for storage, placement new for construction/assignment, and a direct call to the correct destructor in your destructor.

Beware of the alignment issue - you need to ensure that your raw storage is adequately aligned for any of the types you place in it. One way to do this is to dynamically allocate it. Another is to put your char array into a union with whatever built-in type has the greatest alignment requirement (if you don't know: all of them).

The only thing that's different in usage, from the union you want, is that instead of public data members int a, float b, string c, you'll have to provide accessors that return a proxy object (possibly a reference to the object itself), that is capable of assigning correctly, which means calling the destructor for the old type first. Then you can write x.i() = 23 instead of x.i = 23.

Or, you can use Boost.Variant.

べ映画 2024-10-13 15:23:14

这段代码似乎对我来说工作得很好:

typedef union uAA {
    double dVal;
    int iVal[2];

    uAA() : dVal(3.22) {}
} UAA;

main() {
    UAA rdata;

    printf("Array output: %d %d \nDouble output: %lf \n",
        rdata.iVal[0], rdata.iVal[1], rdata.dVal);
}

This code seems to work fine for me:

typedef union uAA {
    double dVal;
    int iVal[2];

    uAA() : dVal(3.22) {}
} UAA;

main() {
    UAA rdata;

    printf("Array output: %d %d \nDouble output: %lf \n",
        rdata.iVal[0], rdata.iVal[1], rdata.dVal);
}
紧拥背影 2024-10-13 15:23:14

您没听错 - 成员的重要构造函数表明该对象旨在封装其数据内容,而联合则删除了该封装。将简单类型的联合放入类中是添加封装的好方法,并确保以合理、安全的方式使用联合内容。

拥有成员的再工会:从 9.5 开始

联合可以有成员函数(包括构造函数和析构函数),但不能有虚拟(10.3)函数。联合不得有基类。联合不得用作基类。具有非平凡构造函数(12.1)、非平凡复制构造函数(12.8)、非平凡析构函数(12.4)或非平凡析构函数(12.4)的类的对象复制赋值运算符(13.5.3、12.8)不能是联合的成员,也不能是此类对象的数组

You've heard right - non-trivial constructors for members suggest the object is meant to encapsulate its data content, and unions remove that encapsulation. Putting a union of simple types into a class is a great way to add encapsulation, and make sure the union content is used in a sensible, safe way.

Re unions having members: from 9.5

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文