เกิดอะไรขึ้น ?
เมื่อคุณสร้าง a Taxiคุณจะสร้างCarsubobject และเมื่อแท็กซี่ถูกทำลายวัตถุทั้งสองจะถูกทำลาย เมื่อคุณโทรหาtest()คุณผ่านCarค่า ดังนั้นวินาทีCarจะได้รับการคัดลอกและจะถูกทำลายเมื่อtest()เหลือ ดังนั้นเราจึงมีคำอธิบายสำหรับนักทำลาย 3 คน: ลำดับแรกและสองคนสุดท้ายในลำดับ
destructor ที่สี่ (นั่นคือลำดับที่สองในลำดับ) ไม่คาดคิดและฉันไม่สามารถทำซ้ำกับคอมไพเลอร์อื่น ๆ ได้
มันสามารถCarสร้างขึ้นชั่วคราวเป็นแหล่งที่มาสำหรับการCarโต้แย้ง เพราะมันไม่ได้เกิดขึ้นเมื่อให้โดยตรงCarค่าเป็นอาร์กิวเมนต์ฉันสงสัยว่าจะเป็นสำหรับการเปลี่ยนเข้าสู่Taxi Carนี่เป็นสิ่งที่คาดไม่ถึงเนื่องจากมีCarsubobject อยู่แล้วในทุกTaxiๆ ดังนั้นฉันคิดว่าคอมไพเลอร์ทำการแปลงที่ไม่จำเป็นลงในอุณหภูมิและไม่ทำการคัดลอกตัวเลือกที่สามารถหลีกเลี่ยงอุณหภูมินี้ได้
ชี้แจงให้ชัดเจนในความคิดเห็น:
นี่คือคำชี้แจงที่มีการอ้างอิงถึงมาตรฐานสำหรับภาษาทนายความเพื่อตรวจสอบการเรียกร้องของฉัน:
- การแปลงที่ฉันอ้างถึงที่นี่คือการแปลงโดยคอนสตรัค
[class.conv.ctor]เตอร์คือการสร้างวัตถุของคลาสหนึ่ง (รถยนต์ที่นี่) ตามอาร์กิวเมนต์ประเภทอื่น (ที่นี่แท็กซี่)
- การแปลงนี้ใช้วัตถุชั่วคราวเพื่อคืน
Carค่า คอมไพเลอร์จะได้รับอนุญาตให้ทำการคัดลอกการคัดลอกตาม[class.copy.elision]/1.1เพราะแทนที่จะสร้างชั่วคราวก็สามารถสร้างค่าที่จะส่งกลับโดยตรงในพารามิเตอร์
- ดังนั้นหากอุณหภูมินี้ให้ผลข้างเคียงก็เป็นเพราะคอมไพเลอร์ไม่ได้ใช้ประโยชน์จากการคัดลอกที่เป็นไปได้นี้ มันไม่ถูกต้องเนื่องจากการคัดลอกจะไม่บังคับ
การยืนยันการทดลองของ anaysis
ตอนนี้ฉันสามารถทำซ้ำกรณีของคุณโดยใช้คอมไพเลอร์เดียวกันและวาดการทดสอบเพื่อยืนยันสิ่งที่เกิดขึ้น
สมมติฐานของฉันข้างต้นก็คือว่าคอมไพเลอร์ที่เลือกเป็นกระบวนการที่ก่อให้เกิดผลลัพธ์พารามิเตอร์ผ่านโดยใช้การแปลงคอนสตรัคCar(const &Taxi)แทนการคัดลอกก่อสร้างโดยตรงจากCarsubobject Taxiของ
ดังนั้นผมจึงพยายามเรียกtest()แต่อย่างชัดเจนหล่อเป็นTaxiCar
ความพยายามครั้งแรกของฉันไม่ประสบความสำเร็จในการปรับปรุงสถานการณ์ คอมไพเลอร์ยังคงใช้การแปลงคอนสตรัคที่ยอดเยี่ยม:
test(static_cast<Car>(taxi)); // produces the same result with 4 destructor messages
ความพยายามครั้งที่สองของฉันสำเร็จ มันจะทำการร่ายด้วยเช่นกัน แต่ใช้การชี้แบบชี้เพื่อแนะนำคอมไพเลอร์อย่างยิ่งให้ใช้Carsubobject ของTaxiและโดยไม่สร้างวัตถุชั่วคราวที่โง่เง่านี้:
test(*static_cast<Car*>(&taxi)); // :-)
และน่าประหลาดใจ: ใช้งานได้ตามที่คาดหวังมีเพียง 3 ข้อความทำลาย :-)
การสรุปการทดลอง:
ในการทดสอบขั้นสุดท้ายฉันได้ให้ตัวสร้างแบบกำหนดเองโดยการแปลง:
class Car {
...
Car(const Taxi& t); // not necessary but for experimental purpose
};
*this = *static_cast<Car*>(&taxi);และดำเนินการด้วย ฟังดูงี่เง่า แต่สิ่งนี้ก็สร้างรหัสที่จะแสดงเฉพาะข้อความ destructor 3 ข้อความเท่านั้นดังนั้นการหลีกเลี่ยงวัตถุชั่วคราวที่ไม่จำเป็น
สิ่งนี้นำไปสู่การคิดว่าอาจมีข้อผิดพลาดในคอมไพเลอร์ที่ทำให้เกิดพฤติกรรมนี้ มันอยู่ที่ความเป็นไปได้ของการคัดลอกโดยตรงจากคลาสฐานที่จะพลาดในบางสถานการณ์
Taxiวัตถุไปยังฟังก์ชันที่รับค่าCarวัตถุ?