C++ Academy · บทเรียน

ยูเนียนและความเสี่ยง

ใช้หน่วยความจำร่วมกันระหว่างชนิด

บทเรียน 2 จาก 413 ขั้นตอน

ยูเนียนและความเสี่ยง เป็นบทเรียน C++ Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C++ Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

ยูเนียนคืออะไร

union ทำให้สมาชิกหลายตัวใช้หน่วยความจำเดียวกันได้ โดยมีสมาชิกที่ใช้งานได้เพียงหนึ่งตัวในแต่ละครั้ง และยูเนียนจะมีขนาดเท่ากับสมาชิกที่ใหญ่ที่สุดเท่านั้น

#include <iostream>
union Number {
    int i;
    float f;
};
int main() {
    Number n;
    n.i = 42;
    std::cout << n.i << "\n";
}

ขนาดของยูเนียน

เนื่องจากสมาชิกใช้พื้นที่ทับซ้อนกัน sizeof ของยูเนียนจึงเท่ากับขนาดของสมาชิกที่ใหญ่ที่สุด รวมถึงพื้นที่จัดแนวที่อาจมีเพิ่ม ไม่ใช่ผลรวมของสมาชิกทั้งหมด

#include <iostream>
union Mix { char c; int i; double d; };
int main() {
    std::cout << sizeof(Mix) << "\n"; // size of double (often 8)
}

การเขียนสมาชิกหนึ่งและอ่านอีกสมาชิกหนึ่ง

การเขียนสมาชิกหนึ่งแล้วอ่านสมาชิกอื่นคือ ความเสี่ยงสำคัญ บิตจะถูกตีความใหม่ ซึ่งมักทำให้เกิดพฤติกรรมไม่กำหนดหรือผลลัพธ์ที่น่าประหลาดใจ

#include <iostream>
union Bits { int i; float f; };
int main() {
    Bits b;
    b.f = 1.0f;
    std::cout << b.i << "\n"; // reads float bits as int
}

สมาชิกที่ใช้งานอยู่เพียงหนึ่งเดียว

สมาชิกที่คุณเขียนล่าสุดคือสมาชิกเพียงตัวเดียวที่สามารถอ่านได้อย่างปลอดภัย คุณต้องติดตามเองว่าสมาชิกใด "ใช้งานอยู่" เพราะยูเนียนจะไม่จดจำข้อมูลนี้

#include <iostream>
union Value { int i; double d; };
int main() {
    Value v;
    v.d = 3.14;        // d is active
    std::cout << v.d << "\n";
}

รูปแบบยูเนียนติดแท็ก

หากต้องการใช้ยูเนียนอย่างปลอดภัย ให้จับคู่กับ แท็ก (ชนิดแจกแจง) ซึ่งบันทึกว่าสมาชิกใดกำลังใช้งานอยู่ นี่คือแนวคิดรุ่นก่อนหน้าที่ทำด้วยตนเองของ std::variant

#include <iostream>
struct Tagged {
    enum { Int, Double } tag;
    union { int i; double d; };
};
int main() {
    Tagged t; t.tag = Tagged::Int; t.i = 7;
    if (t.tag == Tagged::Int) std::cout << t.i << "\n";
}

การอ่านสมาชิกที่ถูกต้อง

ตรวจสอบแท็กก่อนอ่านทุกครั้ง การอ่านสมาชิกที่ไม่ถูกต้องจะให้ค่าขยะ

#include <iostream>
struct Tagged {
    enum { Int, Double } tag;
    union { int i; double d; };
};
void print(const Tagged& t) {
    if (t.tag == Tagged::Int) std::cout << "int " << t.i << "\n";
    else std::cout << "double " << t.d << "\n";
}
int main() { Tagged t{Tagged::Double}; t.d = 2.5; print(t); }

สมาชิกที่ไม่ใช่ชนิดพื้นฐาน

การใส่สมาชิกที่มีตัวสร้างหรือตัวทำลาย (เช่น std::string) ไว้ในยูเนียน จำเป็นต้องสร้างและทำลายด้วยตนเอง ซึ่งมีโอกาสเกิดข้อผิดพลาดได้ง่าย และเป็นอีกเหตุผลหนึ่งที่ควรเลือกใช้ std::variant

ยูเนียนนิรนาม

ยูเนียนนิรนามไม่มีชื่อ โดยเข้าถึงสมาชิกของยูเนียนได้โดยตรง เหมาะสำหรับใช้ภายในโครงสร้าง แต่ยังคงต้องปฏิบัติตามกฎของสมาชิกที่ใช้งานอยู่เช่นเดิม

#include <iostream>
struct Packet {
    int kind;
    union { int code; char letter; };
};
int main() {
    Packet p; p.kind = 1; p.code = 99;
    std::cout << p.code << "\n";
}

เหตุใดยูเนียนจึงมีความเสี่ยง

สรุปอันตราย:

  • ไม่มีข้อมูลว่าสมาชิกใดกำลังใช้งานอยู่
  • การอ่านสมาชิกที่ไม่ได้ใช้งานอยู่เป็นพฤติกรรมไม่กำหนด
  • ชนิดที่ไม่ใช่ชนิดพื้นฐานต้องจัดการอายุการใช้งานด้วยตนเอง

กรณีที่ยูเนียนยังมีประโยชน์

ยูเนียนยังมีประโยชน์สำหรับงานระดับต่ำ เช่น การตีความไบต์ใหม่ การประหยัดหน่วยความจำในโค้ดระบบฝังตัวที่มีข้อจำกัด หรือการจับคู่กับโครงสร้างไบนารีแบบตายตัว สำหรับข้อมูลที่เป็น "หนึ่งชนิดจากหลายชนิด" ในการใช้งานทั่วไป ควรเลือกทางเลือกที่ปลอดภัยกว่า

มุ่งสู่ std::variant

std::variant คือยูเนียนที่ปลอดภัยด้านชนิดข้อมูล ซึ่งติดตามชนิดที่ใช้งานอยู่ให้คุณ และจะโยนข้อยกเว้นหากคุณเข้าถึงชนิดที่ไม่ถูกต้อง บทเรียนที่เหลือของหลักสูตรนี้จะสำรวจเรื่องดังกล่าว

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ตรวจสอบความเข้าใจของคุณเกี่ยวกับยูเนียน

ทบทวน

คุณได้เรียนรู้เกี่ยวกับ ยูเนียน:

  • สมาชิกทั้งหมดใช้บล็อกหน่วยความจำเดียวกัน
  • สมาชิกที่อ่านได้อย่างถูกต้องมีเพียงสมาชิกที่เขียนล่าสุด
  • ใช้แท็ก (ชนิดแจกแจง) เพื่อติดตามสมาชิกที่กำลังใช้งานอยู่
  • เลือกใช้ std::variant เพื่อความปลอดภัยใน C++ สมัยใหม่
เริ่มต้นได้ฟรี

เรียนรู้ C++ ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
51
บทเรียน
203

คำถามที่พบบ่อย

บทเรียน “ยูเนียนและความเสี่ยง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ยูเนียนและความเสี่ยง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C++ Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ยูเนียนและความเสี่ยง”

ใช้หน่วยความจำร่วมกันระหว่างชนิด คุณปฏิบัติ C++ Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C++ Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C++ Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ยูเนียนและความเสี่ยง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C++ Academy นี้ได้ไหม

ได้ บทเรียน C++ Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. enum class แบบมีขอบเขต
  2. ยูเนียนและความเสี่ยง
  3. std::variant
  4. std::visit
← กลับไปที่ C++ Academy