วัตถุประสงค์ของการใช้สหภาพกับสมาชิกเพียงคนเดียวคืออะไร?


89

เมื่อฉันอ่านซอร์สโค้ด seastarฉันสังเกตเห็นว่ามีโครงสร้างแบบสหภาพที่เรียกว่าtx_sideมีสมาชิกเพียงคนเดียว แฮ็คนี้จะจัดการกับปัญหาบางอย่างหรือไม่?

FYI ฉันวาง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เป็นหนึ่งในความแตกต่างระหว่างสองอย่างนี้ มันเป็นเทคนิคที่ค่อนข้างคลุมเครือดังนั้นหากผู้เขียนต้นฉบับของรหัสนั้นมาพร้อมฉันไม่แน่ใจว่าใครบางคนสามารถให้คำตอบที่มีสิทธิ์ซึ่งปัญหาที่พวกเขาหวังว่าจะแก้ไขด้วย (ถ้ามี)
Max Langhof

2
ฉันเดาได้ดีที่สุดว่าการรวมกันนั้นใช้เพื่อชะลอการสร้าง (ซึ่งค่อนข้างไม่มีจุดหมายในกรณีนี้) หรือป้องกันการทำลาย (ซึ่งนำไปสู่การรั่วไหลของหน่วยความจำ) ของ pending_fifo แต่ยากที่จะพูดโดยไม่มีตัวอย่างการใช้งาน
Konstantin Stupnik

คำตอบ:


82

เนื่องจากtx_sideเป็นสหภาพtx_side()ไม่เริ่มต้น / สร้างโดยอัตโนมัติaและ~tx_side()ไม่ทำลายโดยอัตโนมัติ สิ่งนี้ทำให้สามารถควบคุมอายุการใช้งานของaและpending_fifoผ่านตำแหน่งใหม่และคู่มือ destructor โทร (คนจนstd::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เป็นstruct, B()จะเรียกA()และ~B()จะเรียก~A()และคุณจะไม่สามารถที่จะป้องกันไม่ให้


23
@daoliker ไม่จำเป็นต้องสุ่ม แต่คุณคาดเดาไม่ได้ เหมือนกับตัวแปรอื่น ๆ ที่ไม่มีการกำหนดค่าเริ่มต้น คุณไม่สามารถสรุปได้ว่ามันสุ่ม สำหรับสิ่งที่คุณรู้ว่ามันสามารถเก็บรหัสผ่านของผู้ใช้ที่คุณขอให้พวกเขาพิมพ์มาก่อนหน้านี้
user253751

5
@daoliker: ความคิดเห็นก่อนหน้านี้เป็นแง่ดีเกินไป สุ่มไบต์จะมีค่าในช่วง 0-255 แต่ถ้าคุณอ่านไบต์เตรียมเป็นคุณอาจได้รับint 0xCCCCCCCCการอ่านข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้นคือพฤติกรรมที่ไม่ได้กำหนดและสิ่งที่อาจเกิดขึ้นคือคอมไพเลอร์จะยกเลิกความพยายาม นี่ไม่ใช่แค่ทฤษฎี เดเบียนทำผิดพลาดอย่างแน่นอนและทำให้การติดตั้ง OpenSSL ของพวกเขาหยุดชะงัก พวกเขามีบางไบต์สุ่มจริงเพิ่มตัวแปร uninitialized และคอมไพเลอร์กล่าวว่า "ผลที่ได้คือไม่ได้กำหนดดังนั้นมันอาจจะเป็นศูนย์" เห็นได้ชัดว่าไม่มีการสุ่มอีกต่อไป
MSalters

1
@MSalters: คุณมีที่มาสำหรับการอ้างสิทธิ์นี้หรือไม่? เพราะสิ่งที่ฉันสามารถค้นหาได้แสดงให้เห็นว่าไม่ใช่สิ่งที่เกิดขึ้น: มันไม่ใช่คอมไพเลอร์ที่ลบมันออก แต่เป็นนักพัฒนา สุจริตฉันจะประหลาดใจหากผู้เขียนรวบรวมทำการตัดสินใจที่ไม่ดีอย่างไม่น่าเชื่อ (ดูstackoverflow.com/questions/45395435/… )
Jack Aidley

5
@JackAidley: ข้อเรียกร้องที่แม่นยำ? คุณมีลิงค์ดีดูเหมือนว่าฉันได้รับเรื่องราวกลับหัว OpenSSL ผิดตรรกะและใช้ตัวแปรที่ไม่มีการกำหนดค่าเริ่มต้นในลักษณะที่คอมไพเลอร์สามารถยอมรับผลลัพธ์ได้ตามกฎหมาย เดเบียนเห็นอย่างถูกต้องแล้ว แต่การแก้ไขไม่ดี สำหรับ "ผู้รวบรวมผู้ตัดสินใจที่ไม่ดี"; พวกเขาไม่ได้ทำการตัดสินใจ พฤติกรรมที่ไม่ได้กำหนดเป็นการตัดสินใจที่ไม่ดี เครื่องมือเพิ่มประสิทธิภาพได้รับการออกแบบให้ทำงานบนรหัสที่ถูกต้อง ตัวอย่างเช่น GCC สมมติว่าไม่มีการโอเวอร์โฟลว์ที่ลงชื่อ การสันนิษฐานว่า "ไม่มีข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้น" มีความสมเหตุสมผลเท่ากัน มันสามารถใช้ในการกำจัดเส้นทางรหัสเป็นไปไม่ได้
MSalters

1
@JackAidley ฉันพบปัญหาที่คล้ายกันกับสิ่งที่ @MSalters พูดถึงในรหัสของฉันเอง ฉันสันนิษฐานว่าตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นจะว่างเปล่าและรู้สึกงุนงงเมื่อการ!= 0เปรียบเทียบภายหลังให้ผลจริง ฉันได้เพิ่มธงคอมไพเลอร์เพื่อจัดการกับตัวแปรที่ไม่กำหนดค่าเริ่มต้นเป็นข้อผิดพลาดเพื่อให้แน่ใจว่าฉันจะไม่ตกหลุมพรางนั้นอีก
Tom Lint

0

ในคำง่าย ๆ ยกเว้นว่าได้รับมอบหมายอย่างชัดเจน / เริ่มต้นค่าสหภาพเดียวสมาชิกไม่ได้เริ่มต้นหน่วยความจำที่จัดสรร สามารถใช้ฟังก์ชันนี้ได้std:: optionalใน c ++ 17


2
นั่นเป็นคำตอบที่ทำให้เข้าใจผิด ยูเนี่ยนที่มีสมาชิกเพียงคนเดียวจะมีขนาดเท่ากับสมาชิก หน่วยความจำนี้จะไม่เริ่มต้นจนกว่าสมาชิกจะเริ่มต้น
Kirill Dmitrenko
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.