POD ประเภทใดใน C ++


977

ฉันเจอคำศัพท์ประเภท POD สองสามครั้ง
มันหมายความว่าอะไร?



5
โปรดดู chat.stackoverflow.com/transcript/message/213026#213026และข้อความของวันต่อไปนี้สำหรับการอภิปรายเกี่ยวกับคำตอบที่ยอมรับ
Johannes Schaub - litb


@ paxos1977: โปรดเปลี่ยนการเลือกของคุณ "แก้ปัญหา" (ปัจจุบันคำตอบของฮิวกิลล์) เพื่อให้คำตอบที่ผิดขั้นพื้นฐานไม่ได้ทำให้เข้าใจผิดชาว Google ที่จบลงที่นี่
ไชโยและ hth - Alf

เราได้ข้อสรุปว่าสตริงแบบ c ไม่ใช่ชนิด POD เนื่องจาก 1. ) ตัวชี้ไม่ได้ต่อเนื่องกับข้อมูลสตริงและ 2) เพื่อให้สตริงเป็นชนิด POD คุณจะต้องแน่ใจว่าเป็นประเภท มีอักขระถ่านระยะในขนาดที่กำหนดไว้ล่วงหน้าของประเภท POD นำไปสู่พฤติกรรมที่ไม่ได้กำหนด

คำตอบ:


694

PODย่อมาจากPlain Old Data - นั่นคือคลาส (ไม่ว่าจะกำหนดด้วยคีย์เวิร์ดstructหรือคีย์เวิร์ดclass) โดยไม่มีฟังก์ชัน constructors, destructors และฟังก์ชันสมาชิกเสมือน บทความของ Wikipedia เกี่ยวกับ PODจะมีรายละเอียดเพิ่มเติมเล็กน้อยและกำหนดเป็น:

โครงสร้างข้อมูลเก่าแบบธรรมดาใน C ++ เป็นคลาสรวมที่มี PODS เท่านั้นในฐานะสมาชิกไม่มี destructor ที่ผู้ใช้กำหนดเองไม่มีโอเปอเรเตอร์การคัดลอกที่ผู้ใช้กำหนดเองและไม่มีสมาชิกแบบสแตติกต่อสมาชิก

รายละเอียดมากขึ้นสามารถพบได้ในคำตอบนี้สำหรับ C C ++ 11 การเปลี่ยนแปลงกฎระเบียบรอบ POD ผ่อนคลายพวกเขาอย่างมากจึงจำเป็นต้องมีคำตอบที่ติดตามที่นี่


34
มีความแตกต่าง ประเภทที่แท้จริงคือภาษาดั้งเดิม "builtin" ประเภทของ POD คือสิ่งเหล่านี้รวมถึงการรวมตัวของเหล่านี้ (และ POD อื่น ๆ )
Adam Wright

59
ประเภท POD มีคุณสมบัติที่ไม่ใช่ประเภท POD ตัวอย่างเช่นถ้าคุณมีโกลบอล, const, POD-type struct คุณสามารถเริ่มต้นเนื้อหาของมันด้วยเครื่องหมายวงเล็บปีกกามันจะถูกใส่เข้าไปในหน่วยความจำแบบอ่านอย่างเดียวและไม่จำเป็นต้องสร้างรหัสเพื่อเริ่มต้นมัน (คอนสตรัคหรืออย่างอื่น) เพราะมันเป็นส่วนหนึ่งของอิมเมจโปรแกรม สิ่งนี้มีความสำคัญสำหรับผู้ใช้แบบฝังที่มักจะมีข้อ จำกัด เรื่อง RAM, ROM หรือ Flash
Mike DeSimone

34
ใน C ++ 11 คุณสามารถทำ std :: is_pod <MyType> () เพื่อบอกว่า MyType เป็น POD
allyourcode

7
รายงานทางเทคนิคของ Bjarne Stroustrup เกี่ยวกับ C ++ Performanceระบุว่ามาตรฐาน C ++ อธิบาย POD ว่าเป็น " ชนิดข้อมูลที่เข้ากันได้กับชนิดข้อมูลที่เทียบเท่าใน C ในโครงร่างการกำหนดค่าเริ่มต้นและความสามารถในการคัดลอกด้วย memcpy " บางทีความแตกต่างควรทำระหว่างประเภท POD และโครงสร้าง POD
user34660

6
−1คำตอบนี้ยังคงผิดพลาดโดยพื้นฐานและทำให้เข้าใจผิด ณ วันที่ 16 ส.ค. 2559: ประเภท POD ไม่ได้ถูก จำกัด ให้เป็นประเภทชั้นเรียน
ไชโยและ hth - Alf

352

ไม่เป็นทางการมาก:

POD เป็นประเภท (รวมถึงคลาส) ที่คอมไพเลอร์ C ++ รับประกันว่าจะไม่มี "เวทย์มนตร์" เกิดขึ้นในโครงสร้าง: ตัวอย่างเช่นพอยน์เตอร์ที่ซ่อนอยู่กับ vtables ออฟเซ็ตที่นำไปใช้กับที่อยู่เมื่อมันถูกส่งไปยังประเภทอื่น ๆ อย่างน้อยถ้า POD ของเป้าหมายนั้น), constructor หรือ destructors การพูดแบบคร่าวๆประเภทหนึ่งคือ POD เมื่อสิ่งเดียวที่อยู่ในประเภทนั้นเป็นประเภทที่มีอยู่แล้วและการรวมกันของสิ่งเหล่านั้น ผลที่ได้คือสิ่งที่ "ทำหน้าที่เหมือน" ประเภท C

น้อยไม่เป็นทางการ:

  • int, char, wchar_t, bool, float, doubleมีฝักเช่นเดียวกับlong/shortและsigned/unsignedรุ่นของพวกเขา
  • พอยน์เตอร์ (รวมถึง pointer-to-function และ pointer-to-member) คือ POD
  • enums เป็น POD
  • a constหรือvolatilePOD เป็น POD
  • a class, structหรือunionPODs เป็น POD โดยที่สมาชิกข้อมูลไม่คงที่ทั้งหมดpublicและไม่มีคลาสฐานและไม่มีคอนสตรัคเตอร์, destructors หรือวิธีการเสมือน สมาชิกสแตติกไม่หยุดสิ่งที่เป็น POD ภายใต้กฎนี้ กฎนี้มีการเปลี่ยนแปลงใน C ++ 11 และอนุญาตให้สมาชิกส่วนตัวบางคน: คลาสที่มีสมาชิกส่วนตัวทั้งหมดสามารถเป็นคลาส POD ได้หรือไม่
  • Wikipedia นั้นผิดที่จะบอกว่า POD ไม่สามารถมีสมาชิกประเภท pointer-to-member หรือค่อนข้างถูกต้องสำหรับถ้อยคำ C ++ 98 แต่ TC1 ระบุไว้อย่างชัดเจนว่า pointers-to-member คือ POD

เป็นทางการ (มาตรฐาน C ++ 03):

3.9 (10): "ประเภทคณิตศาสตร์ (3.9.1), ประเภทการนับ, ประเภทตัวชี้และตัวชี้ไปยังประเภทสมาชิก (3.9.2) และรุ่นที่ผ่านการรับรอง cv ประเภทเหล่านี้ (3.9.3) เป็นประเภทสเกลาร์ของผู้โทร ประเภท, ประเภท POD-struct, ชนิดของ POD-union (ข้อ 9), อาร์เรย์ของประเภทดังกล่าวและรุ่นที่ผ่านการรับรองด้วย cv ของประเภทเหล่านี้ (3.9.3) เรียกรวมกันว่าประเภท POD "

9 (4): "POD-struct เป็นคลาสรวมที่ไม่มีสมาชิกข้อมูลที่ไม่คงที่ประเภท non-POD-struct, non-POD-union (หรืออาร์เรย์ของประเภทดังกล่าว) หรือการอ้างอิงและไม่มีผู้ใช้ - กำหนดตัวดำเนินการคัดลอกและไม่มี destructor ที่ผู้ใช้กำหนดในทำนองเดียวกัน POD-union เป็นสหภาพรวมที่ไม่มีสมาชิกข้อมูลที่ไม่คงที่ประเภท non-POD-struct, non-POD-union (หรืออาร์เรย์ประเภทดังกล่าว) หรือการอ้างอิง และไม่มีตัวดำเนินการคัดลอกที่ผู้ใช้กำหนดและไม่มีตัวทำลายที่ผู้ใช้กำหนด

8.5.1 (1): "การรวมเป็นอาร์เรย์หรือคลาส (ข้อ 9) โดยไม่มีคอนสตรัคเตอร์ที่ประกาศโดยผู้ใช้ (12.1) ไม่มีสมาชิกข้อมูลส่วนตัวหรือการป้องกันแบบคงที่ (ข้อ 11) ไม่มีคลาสพื้นฐาน (ข้อ 10) และไม่มีฟังก์ชั่นเสมือน (10.3) "


3
คุณเป็นทางการ / เป็นทางการน้อยกว่า คุณสามารถเพิ่มกฎง่ายๆ บิวด์อินชนิดและการรวมบิวด์อินชนิด (หรืออะไรทำนองนั้น) นอกจากนี้เพื่อให้ได้คำจำกัดความที่แน่นอนเราจำเป็นต้องทำให้ความรู้ใช้งานง่าย
Martin York

1
คุณผิดเล็กน้อยในบิต "ออฟเซ็ตเมื่อcast_toประเภทอื่น" ออฟเซ็ตเหล่านั้นจะถูกนำไปใช้เมื่อส่งไปยังคลาสพื้นฐานหรือคลาสที่ได้รับ ดังนั้นหากคุณส่งจากตัวชี้คลาสพื้นฐาน POD ไปเป็นคลาสที่ไม่ได้มาจาก POD คุณอาจยังคงมีการปรับเปลี่ยน
MSalters

1
@ Steve Jessop: ทำไมเราต้องแยกความแตกต่างระหว่าง POD และไม่ใช่ POD เลย?
Lazer

6
@ Lazer: นั่นเป็นคำถามอื่น ๆ ทั้งหมด "PODs ทำงานอย่างไร?" ตรงข้ามกับ "POD หมายถึงอะไร" โดยสรุปความแตกต่างเกี่ยวข้องกับการเริ่มต้น (ดังนั้นจึงใช้ memcpy เพื่อวัตถุที่ซ้ำกัน) เข้ากันได้กับรูปแบบ C struct สำหรับคอมไพเลอร์นั้นและตัวชี้ขึ้นและลงหล่อ PODs "ทำตัวเหมือนประเภท C" ไม่ใช่ POD ที่ไม่รับประกันว่าจะทำเช่นนั้น ดังนั้นหากคุณต้องการให้ประเภทของคุณทำตัวเหมือนพอร์ต C คุณต้องแน่ใจว่ามันเป็น POD ดังนั้นคุณต้องรู้ถึงความแตกต่าง
Steve Jessop

4
@muntoo: ได้รับจริงๆฉันแสดงความคิดเห็นในคำตอบที่พูดถึงข้อมูลที่ล้าสมัยจาก Wikipedia ฉันสามารถแก้ไขคำตอบนั้นได้ แต่ถ้าฉันไปแก้ไขคำตอบของคนอื่นให้เห็นด้วยกับฉันไม่ว่าฉันจะคิดถูก
Steve Jessop

20

ข้อมูลเก่าแบบธรรมดา

ในระยะสั้นก็คือทั้งหมดในตัวชนิดข้อมูล (เช่นint, char, float, long, unsigned char, doubleรวม, ฯลฯ ) และข้อมูลทั้งหมดของ POD ใช่มันเป็นนิยามที่เกิดซ้ำ ;)

เพื่อให้ชัดเจนยิ่งขึ้น POD คือสิ่งที่เราเรียกว่า "a struct": หน่วยหรือกลุ่มของหน่วยที่เพิ่งเก็บข้อมูล


12
มันเป็นความจริงที่บางครั้งเราเรียกพวกเขาว่า 'โครงสร้าง' อย่างไรก็ตามเราทำผิดพลาดเสมอเนื่องจากโครงสร้างไม่จำเป็นต้องเป็นแบบ POD
Steve Jessop

6
อย่างเห็นได้ชัด ... struct และชั้นเทียบเท่าเกือบ แต่ใน "ธุรกิจ" ที่เราเรียกว่า 'a struct' เก็บข้อมูลง่ายมักจะไม่มี ctors และ dtor มักจะมีความหมายค่า ...
ugasoft

2
สำหรับฉันมันผิด C ++ ที่จะทำให้ struct เหมือนกันกับคีย์เวิร์ดของคลาสหรือใกล้กับ: struct เพียงเพิ่มการเข้าถึงคลาสเริ่มต้นสาธารณะเท่านั้น ฉันง่ายกว่าที่จะสร้าง C-like และเราจะมี POD ในวันที่ 0 ของ c ++
user1708042

ugasoft: คำตอบของคุณอาจทำให้เข้าใจผิด - ความคิดเห็นของคุณอธิบายรายละเอียดที่หายไปที่ใช้ในทางปฏิบัติมากกว่ามาตรฐาน อ๊ะ 8 ปีคุณอยู่ที่นี่เหรอ? ;-)
hauron

ด้วยข้อยกเว้นของสตริงเนื่องจากคุณไม่สามารถคัดลอกด้วย memcpy โดยไม่ต้องพิจารณาความยาวของสตริงก่อน

12

ที่ฉันเข้าใจ POD (PlainOldData) เป็นเพียงข้อมูลดิบ - มันไม่จำเป็นต้อง:

  • ที่จะสร้าง
  • จะถูกทำลาย
  • ที่จะมีผู้ประกอบการที่กำหนดเอง
  • ต้องไม่มีฟังก์ชันเสมือน
  • และจะต้องไม่แทนที่โอเปอเรเตอร์

จะตรวจสอบได้อย่างไรว่าอะไรคือ POD มีโครงสร้างสำหรับที่เรียกว่าstd::is_pod:

namespace std {
// Could use is_standard_layout && is_trivial instead of the builtin.
template<typename _Tp>
  struct is_pod
  : public integral_constant<bool, __is_pod(_Tp)>
  { };
}

(จากส่วนหัว type_traits)


อ้างอิง:


2
ไม่ถูกต้องประเภท POD อาจมีฟังก์ชั่นสมาชิกหรือโอเปอเรเตอร์ที่โอเวอร์โหลด (แต่อาจไม่มีฟังก์ชั่นสมาชิกเสมือน)
Colin D Bennett

@ ColinDBennett ใช่นั่นเป็นเรื่องจริง ขอโทษสำหรับความสับสน. แก้ไขเข้า / ออกจาก anwser
набиячлэвэли

10

วัตถุ POD (ข้อมูลเก่าธรรมดา) มีหนึ่งในประเภทข้อมูลเหล่านี้ - ชนิดพื้นฐาน, ตัวชี้, ยูเนี่ยน, โครงสร้าง, อาร์เรย์หรือคลาส - โดยไม่มีตัวสร้าง ในทางกลับกันวัตถุที่ไม่ใช่ POD เป็นสิ่งที่คอนสตรัคเตอร์มีอยู่ วัตถุ POD เริ่มต้นอายุการใช้งานเมื่อได้รับหน่วยเก็บข้อมูลด้วยขนาดที่เหมาะสมสำหรับประเภทและอายุการใช้งานจะสิ้นสุดลงเมื่อหน่วยเก็บข้อมูลสำหรับวัตถุนั้นถูกนำมาใช้ซ้ำหรือยกเลิกการจัดสรรคืน

ประเภท PlainOldData จะต้องไม่มี:

  • ฟังก์ชั่นเสมือน (ทั้งของตัวเองหรือสืบทอด)
  • คลาสฐานเสมือน (โดยตรงหรือโดยอ้อม)

นิยามที่คลายของ PlainOldData รวมถึงวัตถุที่มีตัวสร้าง; แต่ไม่รวมผู้ที่มีสิ่งใดเสมือน ปัญหาที่สำคัญของชนิด PlainOldData คือไม่ใช่แบบ polymorphic การสืบทอดสามารถทำได้ด้วยประเภท POD อย่างไรก็ตามควรทำเฉพาะสำหรับ ImplementationInheritance (การนำโค้ดกลับมาใช้ใหม่) และไม่ใช่ polymorphism / subtyping

คำจำกัดความทั่วไป (แม้ว่าไม่ถูกต้องอย่างเคร่งครัด) คือประเภท PlainOldData เป็นสิ่งที่ไม่มี VeeTable


คำตอบของ Yuor นั้นดีมาก แต่คำถามนี้ได้รับคำตอบเมื่อ 8 ปีที่แล้วรวมถึงคำตอบที่ดีอีกหลายข้อ คุณสามารถมีส่วนร่วมมากขึ้นดังนั้นถ้าคุณใช้ความรู้ที่จะตอบคำถามที่ยังไม่ได้ตอบ)))
mvidelgauz

10

ทำไมเราต้องแยกความแตกต่างระหว่าง POD และ POD ที่ไม่ใช่เลย?

C ++ เริ่มต้นชีวิตในฐานะเป็นส่วนเสริมของ C ในขณะที่ C ++ ที่ทันสมัยไม่ได้เป็น superset ที่เข้มงวดของ C อีกต่อไปคนยังคงคาดหวังความเข้ากันได้ระดับสูงระหว่างทั้งสอง

พูดโดยคร่าวๆประเภท POD เป็นประเภทที่เข้ากันได้กับ C และที่สำคัญพอ ๆ กันคือเข้ากันได้กับการปรับค่า ABI บางอย่าง

เพื่อให้เข้ากันได้กับ C เราต้องตอบสนองข้อ จำกัด สองข้อ

  1. เลย์เอาต์ต้องเหมือนกับประเภท C ที่สอดคล้องกัน
  2. ประเภทจะต้องผ่านไปและกลับจากฟังก์ชั่นในลักษณะเดียวกับประเภท C ที่สอดคล้องกัน

คุณสมบัติ C ++ บางอย่างไม่สามารถใช้งานได้

เมธอดเสมือนต้องการคอมไพเลอร์เพื่อแทรกพอยน์เตอร์หนึ่งตัวหรือมากกว่าลงในตารางเมธอดเสมือนสิ่งที่ไม่มีอยู่ใน C

ตัวสร้างสำเนาที่ผู้ใช้กำหนดเองย้ายตัวสร้างการคัดลอกการมอบหมายและ destructors มีผลกระทบสำหรับการส่งผ่านพารามิเตอร์และกลับ C ABIs จำนวนมากผ่านและส่งคืนพารามิเตอร์ขนาดเล็กในการลงทะเบียน แต่การอ้างอิงที่ส่งผ่านไปยังผู้ใช้กำหนดตัวสร้าง / assigment / destructor สามารถทำงานกับตำแหน่งหน่วยความจำเท่านั้น

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


8

ตัวอย่างของกรณีที่ไม่ใช่ POD ทั้งหมดที่มีเอฟเฟกต์static_assertC ++ 11 ถึง C ++ 17 และ POD

std::is_pod ถูกเพิ่มเข้ามาใน C ++ 11 ดังนั้นให้ลองพิจารณามาตรฐานนั้นเป็นต้นไปในตอนนี้

std::is_podจะถูกลบออกจาก C ++ 20 ตามที่ระบุไว้ที่https://stackoverflow.com/a/48435532/895245เราจะอัปเดตสิ่งนี้เมื่อการสนับสนุนมาถึงสำหรับการแทนที่

ข้อ จำกัด POD ได้ผ่อนคลายมากขึ้นตามมาตรฐานที่พัฒนาขึ้นฉันตั้งเป้าหมายที่จะครอบคลุมการผ่อนคลายทั้งหมดในตัวอย่างผ่านทาง ifdefs

libstdc ++ มีการทดสอบเล็กน้อยที่: https://github.com/gcc-mirror/gcc/blob/gcc-8_2_0-release/libstdc%2B%2B-v3/testsuite/20_util/is_pod/value.ccแต่มัน น้อยเกินไป ผู้ดูแล: โปรดรวมสิ่งนี้ถ้าคุณอ่านโพสต์ ฉันขี้เกียจที่จะตรวจสอบโครงการ C ++ testsuite ที่กล่าวถึงที่: /software/199708/is-there-a-compliance-test-for-c-compilers

#include <type_traits>
#include <array>
#include <vector>

int main() {
#if __cplusplus >= 201103L
    // # Not POD
    //
    // Non-POD examples. Let's just walk all non-recursive non-POD branches of cppreference.
    {
        // Non-trivial implies non-POD.
        // https://en.cppreference.com/w/cpp/named_req/TrivialType
        {
            // Has one or more default constructors, all of which are either
            // trivial or deleted, and at least one of which is not deleted.
            {
                // Not trivial because we removed the default constructor
                // by using our own custom non-default constructor.
                {
                    struct C {
                        C(int) {}
                    };
                    static_assert(std::is_trivially_copyable<C>(), "");
                    static_assert(!std::is_trivial<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // No, this is not a default trivial constructor either:
                // https://en.cppreference.com/w/cpp/language/default_constructor
                //
                // The constructor is not user-provided (i.e., is implicitly-defined or
                // defaulted on its first declaration)
                {
                    struct C {
                        C() {}
                    };
                    static_assert(std::is_trivially_copyable<C>(), "");
                    static_assert(!std::is_trivial<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }
            }

            // Not trivial because not trivially copyable.
            {
                struct C {
                    C(C&) {}
                };
                static_assert(!std::is_trivially_copyable<C>(), "");
                static_assert(!std::is_trivial<C>(), "");
                static_assert(!std::is_pod<C>(), "");
            }
        }

        // Non-standard layout implies non-POD.
        // https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
        {
            // Non static members with different access control.
            {
                // i is public and j is private.
                {
                    struct C {
                        public:
                            int i;
                        private:
                            int j;
                    };
                    static_assert(!std::is_standard_layout<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // These have the same access control.
                {
                    struct C {
                        private:
                            int i;
                            int j;
                    };
                    static_assert(std::is_standard_layout<C>(), "");
                    static_assert(std::is_pod<C>(), "");

                    struct D {
                        public:
                            int i;
                            int j;
                    };
                    static_assert(std::is_standard_layout<D>(), "");
                    static_assert(std::is_pod<D>(), "");
                }
            }

            // Virtual function.
            {
                struct C {
                    virtual void f() = 0;
                };
                static_assert(!std::is_standard_layout<C>(), "");
                static_assert(!std::is_pod<C>(), "");
            }

            // Non-static member that is reference.
            {
                struct C {
                    int &i;
                };
                static_assert(!std::is_standard_layout<C>(), "");
                static_assert(!std::is_pod<C>(), "");
            }

            // Neither:
            //
            // - has no base classes with non-static data members, or
            // - has no non-static data members in the most derived class
            //   and at most one base class with non-static data members
            {
                // Non POD because has two base classes with non-static data members.
                {
                    struct Base1 {
                        int i;
                    };
                    struct Base2 {
                        int j;
                    };
                    struct C : Base1, Base2 {};
                    static_assert(!std::is_standard_layout<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // POD: has just one base class with non-static member.
                {
                    struct Base1 {
                        int i;
                    };
                    struct C : Base1 {};
                    static_assert(std::is_standard_layout<C>(), "");
                    static_assert(std::is_pod<C>(), "");
                }

                // Just one base class with non-static member: Base1, Base2 has none.
                {
                    struct Base1 {
                        int i;
                    };
                    struct Base2 {};
                    struct C : Base1, Base2 {};
                    static_assert(std::is_standard_layout<C>(), "");
                    static_assert(std::is_pod<C>(), "");
                }
            }

            // Base classes of the same type as the first non-static data member.
            // TODO failing on GCC 8.1 -std=c++11, 14 and 17.
            {
                struct C {};
                struct D : C {
                    C c;
                };
                //static_assert(!std::is_standard_layout<C>(), "");
                //static_assert(!std::is_pod<C>(), "");
            };

            // C++14 standard layout new rules, yay!
            {
                // Has two (possibly indirect) base class subobjects of the same type.
                // Here C has two base classes which are indirectly "Base".
                //
                // TODO failing on GCC 8.1 -std=c++11, 14 and 17.
                // even though the example was copy pasted from cppreference.
                {
                    struct Q {};
                    struct S : Q { };
                    struct T : Q { };
                    struct U : S, T { };  // not a standard-layout class: two base class subobjects of type Q
                    //static_assert(!std::is_standard_layout<U>(), "");
                    //static_assert(!std::is_pod<U>(), "");
                }

                // Has all non-static data members and bit-fields declared in the same class
                // (either all in the derived or all in some base).
                {
                    struct Base { int i; };
                    struct Middle : Base {};
                    struct C : Middle { int j; };
                    static_assert(!std::is_standard_layout<C>(), "");
                    static_assert(!std::is_pod<C>(), "");
                }

                // None of the base class subobjects has the same type as
                // for non-union types, as the first non-static data member
                //
                // TODO: similar to the C++11 for which we could not make a proper example,
                // but with recursivity added.

                // TODO come up with an example that is POD in C++14 but not in C++11.
            }
        }
    }

    // # POD
    //
    // POD examples. Everything that does not fall neatly in the non-POD examples.
    {
        // Can't get more POD than this.
        {
            struct C {};
            static_assert(std::is_pod<C>(), "");
            static_assert(std::is_pod<int>(), "");
        }

        // Array of POD is POD.
        {
            struct C {};
            static_assert(std::is_pod<C>(), "");
            static_assert(std::is_pod<C[]>(), "");
        }

        // Private member: became POD in C++11
        // /programming/4762788/can-a-class-with-all-private-members-be-a-pod-class/4762944#4762944
        {
            struct C {
                private:
                    int i;
            };
#if __cplusplus >= 201103L
            static_assert(std::is_pod<C>(), "");
#else
            static_assert(!std::is_pod<C>(), "");
#endif
        }

        // Most standard library containers are not POD because they are not trivial,
        // which can be seen directly from their interface definition in the standard.
        // /programming/27165436/pod-implications-for-a-struct-which-holds-an-standard-library-container
        {
            static_assert(!std::is_pod<std::vector<int>>(), "");
            static_assert(!std::is_trivially_copyable<std::vector<int>>(), "");
            // Some might be though:
            // /programming/3674247/is-stdarrayt-s-guaranteed-to-be-pod-if-t-is-pod
            static_assert(std::is_pod<std::array<int, 1>>(), "");
        }
    }

    // # POD effects
    //
    // Now let's verify what effects does PODness have.
    //
    // Note that this is not easy to do automatically, since many of the
    // failures are undefined behaviour.
    //
    // A good initial list can be found at:
    // /programming/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special/4178176#4178176
    {
        struct Pod {
            uint32_t i;
            uint64_t j;
        };
        static_assert(std::is_pod<Pod>(), "");

        struct NotPod {
            NotPod(uint32_t i, uint64_t j) : i(i), j(j) {}
            uint32_t i;
            uint64_t j;
        };
        static_assert(!std::is_pod<NotPod>(), "");

        // __attribute__((packed)) only works for POD, and is ignored for non-POD, and emits a warning
        // /programming/35152877/ignoring-packed-attribute-because-of-unpacked-non-pod-field/52986680#52986680
        {
            struct C {
                int i;
            };

            struct D : C {
                int j;
            };

            struct E {
                D d;
            } /*__attribute__((packed))*/;

            static_assert(std::is_pod<C>(), "");
            static_assert(!std::is_pod<D>(), "");
            static_assert(!std::is_pod<E>(), "");
        }
    }
#endif
}

GitHub ต้นน้ำ

ทดสอบกับ:

for std in 11 14 17; do echo $std; g++-8 -Wall -Werror -Wextra -pedantic -std=c++$std pod.cpp; done

บน Ubuntu 18.04, GCC 8.2.0


4

แนวคิดของ POD และลักษณะประเภทstd::is_podจะเลิกใช้ใน C ++ 20 ดูคำถามนี้สำหรับข้อมูลเพิ่มเติม


-7

ด้วย C ++ ข้อมูลเก่าธรรมดาไม่เพียง แต่หมายความว่าสิ่งต่างๆเช่น int, char, etc เป็นประเภทที่ใช้เท่านั้น ข้อมูลเก่าอย่างแท้จริงหมายถึงในทางปฏิบัติที่คุณสามารถนำ memcpy จากที่หนึ่งไปยังอีกที่หนึ่งในหน่วยความจำไปยังที่อื่นและสิ่งต่าง ๆ จะทำงานได้อย่างที่คุณคาดหวัง สิ่งนี้จะแบ่งถ้าคลาสของคุณหรือคลาสใด ๆ ที่คลาสของคุณมีมีในฐานะสมาชิกที่เป็นตัวชี้หรือการอ้างอิงหรือคลาสที่มีฟังก์ชันเสมือน โดยพื้นฐานแล้วหากพอยน์เตอร์จำเป็นต้องเกี่ยวข้องกับบางที่ไม่ใช่ข้อมูลเก่าแบบธรรมดา


6
พอยน์เตอร์ได้รับอนุญาตในโครงสร้าง POD การอ้างอิงไม่ได้
j_random_hacker

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