ซีสีทอง ++ "ตามที่ถ้า" กฎ1กล่าวว่าถ้าติดตามพฤติกรรมของโปรแกรมที่ไม่ได้ขึ้นอยู่กับการดำรงอยู่ของข้อมูลสมาชิกที่ไม่ได้ใช้คอมไพเลอร์ที่ได้รับอนุญาตในการเพิ่มประสิทธิภาพมันออกไป
ตัวแปรสมาชิกที่ไม่ได้ใช้ใช้หน่วยความจำหรือไม่?
ไม่ (หากไม่ได้ใช้งาน "จริงๆ")
มีคำถามสองข้อในใจ:
- พฤติกรรมที่สังเกตได้จะไม่ขึ้นอยู่กับการดำรงอยู่ของสมาชิกเมื่อใด
- สถานการณ์แบบนั้นเกิดขึ้นในโปรแกรมชีวิตจริงหรือไม่?
เริ่มจากตัวอย่าง
ตัวอย่าง
#include <iostream>
struct Foo1
{ int var1 = 5; Foo1() { std::cout << var1; } };
struct Foo2
{ int var1 = 5; int var2; Foo2() { std::cout << var1; } };
void f1() { (void) Foo1{}; }
void f2() { (void) Foo2{}; }
หากเราขอให้gcc รวบรวมหน่วยการแปลนี้ผลลัพธ์จะออกมา:
f1():
mov esi, 5
mov edi, OFFSET FLAT:_ZSt4cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
f2():
jmp f1()
f2
เป็นเช่นเดียวกับและหน่วยความจำที่ไม่เคยใช้ในการเก็บจริงf1
Foo2::var2
( เสียงดังก็ทำคล้าย ๆ กัน )
อภิปรายผล
บางคนอาจบอกว่าสิ่งนี้แตกต่างกันด้วยเหตุผลสองประการ:
- นี่เป็นตัวอย่างที่ไม่สำคัญเกินไป
- โครงสร้างได้รับการปรับให้เหมาะสมทั้งหมดจะไม่นับ
โปรแกรมที่ดีคือการประกอบสิ่งง่ายๆที่ชาญฉลาดและซับซ้อนมากกว่าการวางซ้อนสิ่งที่ซับซ้อนง่ายๆ ในชีวิตจริงคุณเขียนฟังก์ชันง่ายๆมากมายโดยใช้โครงสร้างที่เรียบง่ายกว่าที่คอมไพเลอร์ปรับให้เหมาะสม ตัวอย่างเช่น:
bool insert(std::set<int>& set, int value)
{
return set.insert(value).second;
}
นี่คือตัวอย่างที่แท้จริงของข้อมูลสมาชิก (ที่นี่std::pair<std::set<int>::iterator, bool>::first
) ที่ไม่ได้ใช้งาน เดาอะไร? ได้รับการปรับให้เหมาะสมที่สุด ( ตัวอย่างที่ง่ายกว่าด้วยชุดดัมมี่หากการประกอบนั้นทำให้คุณร้องไห้)
ตอนนี้น่าจะเป็นเวลาที่เหมาะสมที่สุดในการอ่านคำตอบที่ยอดเยี่ยมของ Max Langhof ( โปรดโหวตให้ฉันด้วย) มันอธิบายว่าทำไมในท้ายที่สุดแนวคิดของโครงสร้างจึงไม่สมเหตุสมผลในระดับการประกอบที่คอมไพเลอร์เอาท์พุต
"แต่ถ้าฉันทำ X ความจริงที่ว่าสมาชิกที่ไม่ได้ใช้นั้นได้รับการปรับให้เหมาะสมก็เป็นปัญหา!"
มีความคิดเห็นจำนวนมากที่โต้แย้งว่าคำตอบนี้ต้องผิดเพราะการดำเนินการบางอย่าง (เช่นassert(sizeof(Foo2) == 2*sizeof(int))
) จะทำลายบางสิ่ง
หาก X เป็นส่วนหนึ่งของพฤติกรรมที่สังเกตได้ของโปรแกรม2คอมไพเลอร์จะไม่ได้รับอนุญาตให้ปรับแต่งสิ่งต่างๆให้เหมาะสม มีการดำเนินการจำนวนมากบนวัตถุที่มีสมาชิกข้อมูลที่ "ไม่ได้ใช้" ซึ่งจะมีผลต่อโปรแกรมที่สังเกตได้ หากมีการดำเนินการดังกล่าวหรือหากคอมไพเลอร์ไม่สามารถพิสูจน์ได้ว่าไม่มีการดำเนินการใด ๆ สมาชิกข้อมูลที่ "ไม่ได้ใช้" เป็นส่วนหนึ่งของลักษณะการทำงานที่สังเกตได้ของโปรแกรมและไม่สามารถปรับให้เหมาะสมได้
การดำเนินการที่มีผลต่อพฤติกรรมที่สังเกตได้ ได้แก่ แต่ไม่ จำกัด เพียง:
- การกำหนดขนาดของวัตถุประเภทหนึ่ง (
sizeof(Foo)
)
- รับที่อยู่ของสมาชิกข้อมูลที่ประกาศตามหลัง "ไม่ได้ใช้"
- คัดลอกวัตถุที่มีฟังก์ชั่นเช่น
memcpy
,
- การจัดการการเป็นตัวแทนของวัตถุ (เช่นเดียวกับ
memcmp
)
- คุณสมบัติของวัตถุที่ระเหยได้
- ฯลฯ
1)
[intro.abstract]/1
คำอธิบายความหมายในเอกสารนี้กำหนดเครื่องนามธรรมที่ไม่กำหนดพารามิเตอร์ เอกสารนี้ไม่มีข้อกำหนดเกี่ยวกับโครงสร้างของการใช้งานที่สอดคล้องกัน โดยเฉพาะอย่างยิ่งพวกเขาไม่จำเป็นต้องคัดลอกหรือเลียนแบบโครงสร้างของเครื่องจักรที่เป็นนามธรรม แต่การใช้งานที่สอดคล้องกันนั้นจำเป็นต้องเลียนแบบ (เท่านั้น) พฤติกรรมที่สังเกตได้ของเครื่องจักรนามธรรมตามที่อธิบายไว้ด้านล่าง
2)เช่นเดียวกับการยืนยันว่าผ่านหรือล้มเหลวคือ