มาตรฐานไม่ต้องการการปรับให้เหมาะสมเป็นพิเศษในกรณีของวัตถุข้อยกเว้นที่ไม่มีชื่อ ในทางตรงกันข้าม จะต้องมีผลเหมือนกับว่าชั่วคราวมีการเริ่มต้นการคัดลอก การคัดลอกนี้อาจส่งผลให้มีการจัดสรรหน่วยความจำแบบไดนามิก
N3290 §15.3/16:
หาก การประกาศข้อยกเว้น ระบุชื่อ ก็จะประกาศตัวแปรซึ่งมีการเริ่มต้นการคัดลอก (8.5) จากอ็อบเจ็กต์ข้อยกเว้น หาก การประกาศข้อยกเว้น หมายถึงประเภทวัตถุ แต่ไม่ได้ระบุชื่อ ชั่วคราว (12.2) จะถูกคัดลอกเริ่มต้น (8.5) จากวัตถุข้อยกเว้น อายุการใช้งานของตัวแปรหรือสิ้นสุดชั่วคราวเมื่อตัวจัดการออก หลังจากการทำลายออบเจ็กต์อัตโนมัติใดๆ ที่เริ่มต้นภายในตัวจัดการ
ย่อหน้าข้างต้นไม่ได้กล่าวถึงการจับโดยการอ้างอิง ดังนั้นจึงอาจสรุปได้อย่างสมเหตุสมผลว่าจะใช้หรือไม่ว่าวัตถุข้อยกเว้นจะถูกตรวจจับโดยการอ้างอิงหรือไม่ ว่ามีการสร้างสำเนาอยู่แล้ว
อย่างไรก็ตาม ซึ่งมีความขัดแย้งในย่อหน้าถัดไป:
N3290 §15.3/17:
เมื่อตัวจัดการประกาศวัตถุที่ไม่คงที่ การเปลี่ยนแปลงใด ๆ ในวัตถุนั้นจะไม่ส่งผลกระทบต่อวัตถุชั่วคราวที่เริ่มต้นโดยการดำเนินการของ throw-expression . เมื่อตัวจัดการประกาศการอ้างอิงถึงวัตถุที่ไม่คงที่ การเปลี่ยนแปลงใด ๆ กับวัตถุที่อ้างอิงจะถูกเปลี่ยนไปยังวัตถุชั่วคราวที่เตรียมใช้งานเมื่อ throw-expression ถูกดำเนินการ และจะมีผลหากวัตถุนั้นถูกโยนทิ้งใหม่
ดังนั้น ประเภทที่ประกาศ T&
(ด้วย T
ไม่ใช่-const
) จึงเป็นกรณีเดียวที่ C++11 ต้องการการอ้างอิงโดยตรงไปยังวัตถุที่ถูกโยนทิ้ง แทนที่จะคัดลอก และมันก็เป็นเช่นนั้นใน C++03 ยกเว้นว่า C++03 มีถ้อยคำเพิ่มเติมเกี่ยวกับการเพิ่มประสิทธิภาพเสมือนหนึ่ง ดังนั้น สำหรับการเป็นทางการ ควรมีการตั้งค่าไว้สำหรับ
catch( T& name )
และ
catch( T& )
อย่างไรก็ตาม ฉันมักจะพบข้อยกเว้นเช่น catch( T const& )
เสมอ จากมุมมองเชิงปฏิบัติอาจสันนิษฐานได้ว่าคอมไพเลอร์จะปรับให้เหมาะสมกับการอ้างอิงโดยตรงไปยังวัตถุที่ถูกโยนทิ้ง แม้ว่าจะเป็นไปได้ที่จะกำหนดกรณีที่ผลกระทบของโปรแกรมที่สังเกตได้นั้นไม่ได้มาตรฐานก็ตาม เช่น <evil grin>
#include <stdio.h>
#include <stdexcept>
struct Error
: std::runtime_error
{
public:
static Error* pThrown;
char const* pMessage_;
Error()
: std::runtime_error( "Base class message" )
, pMessage_( "Original message." )
{
printf( "Default-construction of Error object.\n" );
pThrown = this;
}
Error( Error const& other )
: std::runtime_error( other )
, pMessage_( other.pMessage_ )
{
printf( "Copy-construction of Error obejct.\n" );
}
char const* what() const throw() { return pMessage_; }
};
Error* Error::pThrown = 0;
int main()
{
printf( "Testing non-const ref:\n" );
try
{
throw Error();
}
catch( Error& x )
{
Error::pThrown->pMessage_ = "Modified message.";
printf( "%s\n", x.what() );
}
printf( "\n" );
printf( "Testing const ref:\n" );
try
{
throw Error();
}
catch( Error const& x )
{
Error::pThrown->pMessage_ = "Modified message";
printf( "%s\n", x.what() );
}
}
ด้วยทั้ง MinGW g++ 4.4.1 และ Visual C++ 10.0 ผลลัพธ์ก็คือ
Testing non-const ref:
Default-construction of Error object.
Modified message.
Testing const ref:
Default-construction of Error object.
Modified message
ผู้ทำพิธีการแบบอวดรู้อาจบอกว่าคอมไพเลอร์ทั้งสองไม่สอดคล้องกัน ไม่สามารถสร้างสำเนาสำหรับกรณี Error const&
ได้ ผู้ปฏิบัติงานจริงอาจพูดว่า เฮ้ คุณคาดหวังอะไรอีกบ้าง และฉัน ฉันบอกว่าถ้อยคำในมาตรฐานยังห่างไกลจากความสมบูรณ์แบบที่นี่มาก และหากมีอะไรเกิดขึ้น เราควรจะคาดหวังว่าจะมีการชี้แจงเพื่ออนุญาตผลลัพธ์ข้างต้นอย่างชัดเจน เพื่อที่การจับโดยการอ้างอิงถึง const
จะปลอดภัยและมีประสิทธิภาพสูงสุด
สรุป wrt. คำถามของ OP:
การจับโดยการอ้างอิงจะไม่เรียกตัวสร้างการคัดลอกซึ่งอาจยุติโปรแกรมได้
มาตรฐานรับประกันเฉพาะสิ่งนี้สำหรับการอ้างอิงถึง non-const
ในทางปฏิบัติ ดังที่แสดงไว้ มีการรับประกันสำหรับการอ้างอิงถึง const
แม้ว่าผลลัพธ์ของโปรแกรมจะได้รับผลกระทบก็ตาม
ไชโย & hth.,
person
Cheers and hth. - Alf
schedule
13.09.2011
my_exception&
แต่ฉันพบว่าส่วนใหญ่แล้วข้อยกเว้นไม่ได้รับการแก้ไข ดังนั้น จึงควรจับmy_exception const&
จะดีกว่า โปรดทราบว่าwhat
คือconst
- person Matthieu M.   schedule 13.09.2011