เกิดอะไรขึ้น ?
เมื่อคุณสร้าง a Taxi
คุณจะสร้างCar
subobject และเมื่อแท็กซี่ถูกทำลายวัตถุทั้งสองจะถูกทำลาย เมื่อคุณโทรหาtest()
คุณผ่านCar
ค่า ดังนั้นวินาทีCar
จะได้รับการคัดลอกและจะถูกทำลายเมื่อtest()
เหลือ ดังนั้นเราจึงมีคำอธิบายสำหรับนักทำลาย 3 คน: ลำดับแรกและสองคนสุดท้ายในลำดับ
destructor ที่สี่ (นั่นคือลำดับที่สองในลำดับ) ไม่คาดคิดและฉันไม่สามารถทำซ้ำกับคอมไพเลอร์อื่น ๆ ได้
มันสามารถCar
สร้างขึ้นชั่วคราวเป็นแหล่งที่มาสำหรับการCar
โต้แย้ง เพราะมันไม่ได้เกิดขึ้นเมื่อให้โดยตรงCar
ค่าเป็นอาร์กิวเมนต์ฉันสงสัยว่าจะเป็นสำหรับการเปลี่ยนเข้าสู่Taxi
Car
นี่เป็นสิ่งที่คาดไม่ถึงเนื่องจากมีCar
subobject อยู่แล้วในทุกTaxi
ๆ ดังนั้นฉันคิดว่าคอมไพเลอร์ทำการแปลงที่ไม่จำเป็นลงในอุณหภูมิและไม่ทำการคัดลอกตัวเลือกที่สามารถหลีกเลี่ยงอุณหภูมินี้ได้
ชี้แจงให้ชัดเจนในความคิดเห็น:
นี่คือคำชี้แจงที่มีการอ้างอิงถึงมาตรฐานสำหรับภาษาทนายความเพื่อตรวจสอบการเรียกร้องของฉัน:
- การแปลงที่ฉันอ้างถึงที่นี่คือการแปลงโดยคอนสตรัค
[class.conv.ctor]
เตอร์คือการสร้างวัตถุของคลาสหนึ่ง (รถยนต์ที่นี่) ตามอาร์กิวเมนต์ประเภทอื่น (ที่นี่แท็กซี่)
- การแปลงนี้ใช้วัตถุชั่วคราวเพื่อคืน
Car
ค่า คอมไพเลอร์จะได้รับอนุญาตให้ทำการคัดลอกการคัดลอกตาม[class.copy.elision]/1.1
เพราะแทนที่จะสร้างชั่วคราวก็สามารถสร้างค่าที่จะส่งกลับโดยตรงในพารามิเตอร์
- ดังนั้นหากอุณหภูมินี้ให้ผลข้างเคียงก็เป็นเพราะคอมไพเลอร์ไม่ได้ใช้ประโยชน์จากการคัดลอกที่เป็นไปได้นี้ มันไม่ถูกต้องเนื่องจากการคัดลอกจะไม่บังคับ
การยืนยันการทดลองของ anaysis
ตอนนี้ฉันสามารถทำซ้ำกรณีของคุณโดยใช้คอมไพเลอร์เดียวกันและวาดการทดสอบเพื่อยืนยันสิ่งที่เกิดขึ้น
สมมติฐานของฉันข้างต้นก็คือว่าคอมไพเลอร์ที่เลือกเป็นกระบวนการที่ก่อให้เกิดผลลัพธ์พารามิเตอร์ผ่านโดยใช้การแปลงคอนสตรัคCar(const &Taxi)
แทนการคัดลอกก่อสร้างโดยตรงจากCar
subobject Taxi
ของ
ดังนั้นผมจึงพยายามเรียกtest()
แต่อย่างชัดเจนหล่อเป็นTaxi
Car
ความพยายามครั้งแรกของฉันไม่ประสบความสำเร็จในการปรับปรุงสถานการณ์ คอมไพเลอร์ยังคงใช้การแปลงคอนสตรัคที่ยอดเยี่ยม:
test(static_cast<Car>(taxi)); // produces the same result with 4 destructor messages
ความพยายามครั้งที่สองของฉันสำเร็จ มันจะทำการร่ายด้วยเช่นกัน แต่ใช้การชี้แบบชี้เพื่อแนะนำคอมไพเลอร์อย่างยิ่งให้ใช้Car
subobject ของ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
วัตถุ?