メンバーが1つだけの組合を使用する目的は何ですか?


89

seastarのソースコードを読んでいたときに、tx_sideメンバーが1つだけのと呼ばれる共用体構造があることに気付きました。これは特定の問題に対処するためのハックですか?

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
stackoverflow.com/questions/26572432/…の重複の可能性があります。
Max Langhof

5
@MaxLanghofこの質問と対応する回答では、このような共用体構造を使用する目的については触れられていませんでした。
daoliker

このメンバーの使用例はありますか?
n314159

4
そのため、私は実際に拘束力のある終了票を使用していません。しかし、そこにある答えから直接従わない質問への答えからあなたが正確に何を期待しているのかはわかりません。のunion代わりにを使用する目的はstruct、2つの違いの1つまたは複数です。これはかなりあいまいな手法なので、そのコードの元の作者が一緒に来ない限り、誰かがこれで解決したいと考えている問題(ある場合)を信頼できる答えを誰かがあなたに与えることができるかどうかはわかりません。
Max Langhof

2
私の推測では、unionを使用して、建設を遅らせる(この場合は意味がありません)か、pending_fifoの破壊を防ぐ(メモリリークにつながる)のを防ぎます。しかし、使用例なしで言うのは難しいです。
Konstantin Stupnik

回答:


82

tx_sideは和集合であるため、tx_side()自動的に初期化/構築しaたり、~tx_side()自動的に破棄したりしません。これにより、placement-newと手動のデストラクタ呼び出し(貧乏人の)を介して、aとの有効期間をきめ細かく制御できます。pending_fifostd::optional

次に例を示します。

#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だった場合structB()を呼び出しA()、を~B()呼び出し~A()、それを防ぐことはできません。


23
@daolikerは必ずしもランダムではありませんが、予測不可能です。他の初期化されていない変数と同じです。ランダムであるとは限りません。。すべてのためにあなたはそれはあなたが以前に入力し、それらを尋ねたことをユーザーのパスワードを保持する可能性が知っている
user253751

5
@daoliker:前のコメントは楽観的すぎます。ランダムは0〜255の範囲内の値を持っているだろうが、あなたに初期化されていないバイトを読めばバイトintあなたが得ることができます0xCCCCCCCC。初期化されていないデータを読み取ることは未定義の動作であり、コンパイラーがその試みを単に破棄することが起こり得るのです。これは単なる理論ではありません。Debianはこの正確な間違いを犯し、OpenSSLの実装を壊しました。ランダムなバイトがいくつかあり、初期化されていない変数が追加されており、コンパイラーは「結果は未定義なので、ゼロになる可能性がある」と述べています。ゼロはもはやランダムではありません。
MSalters

1
@MSalters:この主張の出典はありますか?私が見つけることができることは、それが起こったことではないことを示唆しているからです。それを削除したのはコンパイラではなく、開発者でした。正直なところ、コンパイラの作成者がそのような信じられないほど悪い決断をしたとしたら、私は驚かれることでしょう。(stackoverflow.com/questions/45395435/…を参照)
Jack Aidley

5
@JackAidley:どの正確な主張ですか?あなたは良いリンクを持っています、私は話を逆にしたようです。OpenSSLはロジックを誤解し、初期化されていない変数を使用して、コンパイラーが合法的に結果を推測できるようにしました。Debianはそれを正しく見つけましたが、修正を壊しました。「そのような悪い決定を下すコンパイラー」に関しては; 彼らはその決定をしません。未定義の動作は悪い決断です。オプティマイザは、正しいコードで実行するように設計されています。たとえばGCCは、符号付きオーバーフローがないことを積極的に想定しています。「初期化されていないデータがない」と仮定することも同様に合理的です。不可能なコードパスを排除するために使用できます。
MSalters

1
@JackAidley @MSaltersが自分のコードで言及しているのと同様の問題が発生しました。初期化されていない変数は空であると誤って想定し、その後の!= 0比較でtrueになると困惑しました。それ以来、初期化されていない変数をエラーとして扱い、再びそのトラップに陥らないようにするためのコンパイラフラグを追加しました。
トム・リント

0

簡単に言えば、値を明示的に割り当て/初期化しない限り、単一メンバーの共用体は割り当てられたメモリを初期化しません。この機能はstd:: optional、c ++ 17で実現できます。


2
それは誤解を招く答えです。メンバーが1人だけのユニオンは、メンバーと同じサイズになります。このメモリは、メンバーが初期化されるまで初期化されません。
Kirill Dmitrenko
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.