只有一个成员的联合体有什么作用?

99
当我阅读seastar源代码时,我注意到有一个名为tx_side的联合结构,只有一个成员。这是处理某个问题的一种技巧吗?
供您参考,下面是tx_side结构:
union tx_side {
    tx_side() {}
    ~tx_side() {}
    void init() { new (&a) aa; }
    struct aa {
        std::deque<work_item*> pending_fifo;
    } a;
} _tx;

1
可能是 https://dev59.com/X18d5IYBdhLWcg3wpzr4 的重复问题。 - Max Langhof
7
此问题及对应回答未提及使用这种联合结构的目的。 - xiaoming-qxm
4
这就是为什么我实际上没有使用我的绑定关闭投票。但我不确定你对问题的答案有什么期望,因为答案并没有直接跟随在那里的答案之后。假定使用 union 而不是 struct 的目的是两者之间的一个或多个差异。这是一种相当晦涩的技术,除非那段代码的原始作者出现,否则我不确定有人能够给你一个权威的答案,说明他们希望用这种方法解决哪些问题(如果有的话)。 - Max Langhof
@n314159 问题中的 seastar源代码 链接就是一个例子。 - xiaoming-qxm
2
我最好的猜测是,联合体被用来延迟构造(在这种情况下有点无意义)或防止销毁(导致内存泄漏)pending_fifo。但是如果没有使用示例很难说。 - Konstantin Stupnik
显示剩余5条评论
2个回答

97
因为tx_side是一个union,所以tx_side()不会自动初始化/构造a~tx_side()也不会自动销毁它。这允许通过放置new和手动析构函数调用(一种拙劣的std::optional)对apending_fifo的生命周期进行细粒度控制。
下面是一个例子:
#include <iostream>

struct A
{
    A() {std::cout << "A()\n";}
    ~A() {std::cout << "~A()\n";}
};

union B
{
    A a;
    B() {}
    ~B() {}
};

int main()
{
    B b;
}

这里,B b; 不会输出任何内容,因为 a 没有被构造或销毁。

如果 B 是一个结构体,B() 将调用 A()~B() 将调用 ~A(),你无法阻止它。


25
@daoliker 不一定是随机的,但你无法预测它。就像任何其他未初始化的变量一样。你不能假设它是随机的;你不知道它可能会保存用户之前要求他们输入的密码。 - user253751
5
@daoliker:前面的评论过于乐观了。随机字节会在0-255范围内具有值,但是如果您将未初始化的字节读入int中,则可能得到0xCCCCCCCC。读取未初始化的数据是未定义行为,可能发生的情况是编译器仅丢弃该尝试。这不仅仅是理论上的问题。Debian犯了这个粗心大意的错误,它破坏了他们的OpenSSL实现。他们拥有一些真正的随机字节,添加了一个未初始化的变量,然后编译器说“结果是未定义的,所以最好是零”。显然,零不再是随机的。 - MSalters
1
@MSalters:你有这个说法的来源吗?因为我所找到的资料表明并不是这样发生的:它不是编译器删除了它,而是开发人员。老实说,如果有任何编译器作者做出如此糟糕的决定,我会感到惊讶的。(见https://dev59.com/0aPia4cB1Zd3GeqP5OLp) - Jack Aidley
5
@JackAidley:哪个具体的声明?你提供了一个好链接,看来我把故事颠倒了。OpenSSL逻辑出了问题,并以这样一种方式使用未初始化的变量,以至于编译器可以合法地假设任何结果。Debian正确地发现了这一点,但却破坏了修复。至于“编译器做出如此糟糕的决定”;他们并没有做出那个决定。未定义行为才是糟糕的决定。优化器是设计用来运行正确代码的。例如,GCC积极假设没有有符号溢出。假设“没有未初始化的数据”同样是合理的;它可以用来消除不可能的代码路径。 - MSalters
1
@MSalters:未定义行为仅意味着它未被标准委员会定义,编译器编写者通常比委员会更加务实,并不会因为委员会说它是UB而表现得极端。 - Jack Aidley
显示剩余13条评论

-1
简单来说,如果没有显式分配/初始化值,单成员联合不会初始化分配的内存。在C++17中,可以使用std::optional实现此功能。

3
这是一个误导性的答案。只有一个成员的联合将具有与该成员相同的大小。这个内存直到成员被初始化之前都不会被初始化。 - Kirill Dmitrenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接