令我驚訝的是,std::runtime_error
只有一個const std::string&
建構式,而沒有值建構式。因此,我想知道是否throw std::runtime_error("Temporary" std::to_string(100));
已定義。畢竟,我們正在創建一個例外物件,它參考了一個函式范圍內的一個臨時物件,該函式立即退出(當我們拋出它時)。進一步的調查表明,雖然回傳對臨時值的常量參考會立即導致我的系統出現段錯誤,但拋出一個不會:
const std::string& undefined_behavior() {
return "Undefined " std::to_string(1);
}
void test() {
throw std::runtime_error("Hello : " std::to_string(2));
}
void test2() {
const std::string& ref = "Hello : " std::to_string(3);
throw ref;
}
int main(int argc, char** argv) {
//std::cout << undefined_behavior() << std::endl;
try {
test();
} catch(const std::runtime_error& ex) {
std::cout << ex.what() << std::endl;
}
try {
test2();
} catch(const std::string& ref) {
std::cout << ref << std::endl;
}
}
在我的系統上,立即undefined_behavior()
崩潰但運行良好。test()
test2()
雖然我知道呼叫undefined_behavior()
是未定義的行為,但 is test()
and test2()
undefined? 如果沒有,拋出的值是否得到指定的處理?
如果它們都未定義但碰巧在我的計算機上作業,那么用可變訊息引發例外的正確方法是什么?
uj5u.com熱心網友回復:
構造const std::string&
函式不會導致例外物件存盤對傳遞的參考std::string
。std::runtime_error
將為傳遞的字串制作一個內部副本(盡管副本將以通常的方式存盤,可能在例外物件外部的分配中進行參考計數;這是為了在復制例外物件時提供更好的例外保證,標準要求)。
采用const
左值參考的函式通常并不意味著它獲得所有權或存盤對物件的參考。
在 C 11 之前,沒有理由不在const
這里使用參考,因為它總是比按值傳遞更有效。隨著 C 11 的移動語意發生了變化,確實通常這些型別的建構式在 C 11 中添加了右值參考變體,因此將臨時std::string
物件傳遞給建構式將允許更有效的移動構造而不是復制建造。
我的猜測是,對于例外類,這根本就沒有完成,因為與實際拋出例外的開銷相比,它們的構造性能應該不重要。
因此,在這種情況下,從操作中創建了test()
一個臨時物件,該物件被傳遞給建構式,例外物件將復制它。在例外物件初始化后,臨時字串被銷毀,但這不是問題,因為例外物件存盤/參考了一個副本。string
如果test2()
你寫過,同樣適用throw std::runtime_error(ref)
。但是,這里的參考立即系結到從 的回傳值具體化的臨時物件
。這會導致它的生命周期延長到參考變數的生命周期。因此,再一次,臨時生命足夠長,std::runtime_error
可以從中復制。
但是,由于您只是簡單地寫throw ref
,這并不完全是發生的事情。throw ref
將拋出一個std::string
,因為那是ref
運算式的型別。但是,throw
實際上并不使用運算式參考的物件作為例外物件。例外物件從運算式的運算元初始化。throw
所以在這里,例外物件將是另一個std::string
物件(在未指定的存盤中),它將從ref
參考的臨時物件中初始化。
undefined_behavior()
使用回傳值時具有未定義的行為,因為臨時std::string
物件從
回傳值具體化并且undefined_behavior()
參考的回傳值沒有生命周期延長。盡管它再次立即被參考系結,但生命周期擴展規則特別不適用于在回傳值初始化中系結到參考的物件。相反,當函式回傳時,臨時物件被銷毀,導致函式總是回傳一個懸空參考。
uj5u.com熱心網友回復:
這不是未定義的行為。
在test1()
中, 的建構式std::runtime_error
進行內部復制。在cppreference甚至有一個注釋:
std::runtime_error
因為不允許復制引發例外,所以此訊息通常在內部存盤為單獨分配的參考計數字串。這也是為什么沒有建構式采用的原因std::string&&
:無論如何它都必須復制內容。
在test2()
沒有std::runtime_error
涉及。相反,您可以在下面的陳述句中閱讀例如here
throw expr;
例外物件是從復制初始化的expr
。因此,在這種情況下,該臨時字串也有一個副本。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/494837.html