Sadece bir üyeyle sendika kullanmanın amacı nedir?


89

Seastar kaynak kodunu okurken tx_side, sadece bir üyesi olan bir birlik yapısı olduğunu fark ettim . Belli bir problemle başa çıkmak hack mi?

Bilginize, tx_sideaşağıdaki yapıyı yapıştırıyorum :

union tx_side {
    tx_side() {}
    ~tx_side() {}
    void init() { new (&a) aa; }
    struct aa {
        std::deque<work_item*> pending_fifo;
    } a;
} _tx;


5
@MaxLanghof Bu soru ve karşılık gelen cevaplar böyle bir birlik yapısının kullanım amacından bahsetmedi.
daoliker

Bu üyeyi kullanmak için bir örnek var mı?
n314159

4
Bu yüzden bağlayıcı yakın oyumu gerçekten kullanmadım. Ancak, doğrudan oradaki cevaplardan sonra gelmeyen sorunuzun cevaplarından tam olarak ne beklediğinizden emin değilim. Muhtemelen unionbunun yerine kullanım amacı struct, ikisi arasındaki farklardan biri veya daha fazlasıdır. Oldukça belirsiz bir teknik olduğundan, bu kodun orijinal yazarı gelmedikçe, birisinin size bu sorunu çözmeyi umdukları yetkili bir cevap verebileceğinden emin değilim (eğer varsa).
Max Langhof

2
En iyi tahminim, birliğin ya inşaatı ertelemek (bu durumda biraz anlamsız) ya da pending_fifo'nun yıkılmasını (bellek sızıntısına yol açan) önlemek için kullanılmasıdır. Ancak kullanım örneği olmadan söylemek zor.
Konstantin Stupnik

Yanıtlar:


82

Çünkü tx_sidebir birliktir, tx_side()otomatik olarak başlatılmaz / yapılandırılmaz ave ~tx_side()onu otomatik olarak yok etmez. Bu, yerleştirme yeni ve manuel yıkıcı çağrıları (fakir bir adamın ) ömrü boyunca ave üzerinde ince bir kontrol sağlar .pending_fifostd::optional

İşte bir örnek:

#include <iostream>

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

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

int main()
{
    B b;
}

Burada B b;hiçbir şey basmıyor, çünkü ane inşa edilmiş ne de yıkılmış.

Eğer Bbir oldu struct, B()çağırır A()ve ~B()çağırır ~A()ve bunu önlemek için mümkün olmaz.


23
@ daoliker mutlaka rastgele değil, sizin öngörülemez. Başlatılmamış diğer değişkenlerle aynı. Rastgele olduğunu varsayamazsınız; tüm bildiğiniz için, daha önce yazmasını istediğiniz kullanıcının şifresini tutabilir.
user253751

5
@daoliker: Önceki yorum çok iyimser. Rasgele baytlar 0-255 aralığında değerlere sahiptir, ancak başlatılmamış bir baytı bir içine okursanız intalabilirsiniz 0xCCCCCCCC. Başlatılmamış verilerin okunması Tanımsız Davranış'tır ve derleyici sadece denemeyi atmasıdır. Bu sadece teori değil. Debian bu hatayı yaptı ve OpenSSL uygulamalarını bozdu. Bazı gerçek rastgele baytları vardı, başlatılmamış bir değişken eklediler ve derleyici "iyi sonuç tanımsız, bu yüzden sıfır da olabilir" dedi. Zero artık rastgele değil.
MSalters

1
@MSalters: Bu iddia için bir kaynağınız var mı? Çünkü bulabildiğim şey bunun olduğunu değil: onu kaldıran derleyici değil, geliştiricilerdi. Dürüst olmak gerekirse, herhangi bir derleyici yazarının inanılmaz derecede kötü bir karar vermesi beni şaşırttı. (bkz. stackoverflow.com/questions/45395435/… )
Jack Aidley

5
@JackAidley: Hangi kesin iddia? İyi bir bağlantınız var, hikayeyi tersine çevirdim. OpenSSL mantığı yanlış anlamış ve başlatılmamış bir değişkeni bir derleyicinin yasal olarak herhangi bir sonuç alabileceği şekilde kullanmıştır. Debian bunu doğru bir şekilde fark etti, ancak düzeltmeyi kırdı. "Bu tür kötü kararlar veren derleyiciler"; bu kararı vermezler. Tanımsız Davranış kötü karardır. Optimize ediciler doğru kodda çalışacak şekilde tasarlanmıştır. Örneğin GCC aktif olarak imzalı taşmayı kabul etmez. "Başlatılmamış veri yok" varsayımı aynı derecede makuldür; imkansız kod yollarını ortadan kaldırmak için kullanılabilir.
MSalters

1
@JackAidley @MSalters'in kendi kodumda bahsettiklerine benzer sorunlarla karşılaştım; Yanlışlıkla başlatılmamış bir değişkenin boş olacağını ve sonraki bir != 0karşılaştırma doğru olduğunda şaşkına döndüm . Başlamamış değişkenleri hata olarak tedavi etmek için derleyici bayrakları ekledim ve tekrar bu tuzağa düşmeyeceğimden emin oldum.
Tom Lint

0

Basit bir ifadeyle, açıkça bir değer atanmadıkça / başlatılmadıkça, tek üye birliği ayrılan belleği başlatmaz. Bu işlevsellik std:: optionalc ++ 17 ile elde edilebilir .


2
Bu yanıltıcı bir cevap. Sadece bir üyeli sendika, üye ile aynı boyuta sahip olacaktır. Bu bellek, üye başlatılana kadar başlatılmaz.
Kirill Dmitrenko
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.