我發現運行這個用 clang 編譯的一小段代碼有一個奇怪的行為:
#include <iostream>
#include <exception>
#include <typeinfo>
struct Foo : public std::exception {
std::string myString;
Foo(const std::string& str) : myString(str) {}
Foo() : Foo(typeid(*this).name()) {}
};
int main()
{
Foo f;
std::cout << f.myString;
}
typeid(*this).name()在委托建構式中呼叫的指令回傳nullptr導致分段錯誤的指令。在委托的建構式呼叫期間,std::exception基類尚未初始化,這似乎是導致此行為的原因。
我想知道這段代碼是否由于某種原因格式錯誤,或者這種行為是預期的。
我無法使用 g 重現此錯誤,其中代碼運行良好。
它也僅在基類是 std::exception 時才會發生,在任何其他情況下,即使在 clang 上它也能正常作業。
uj5u.com熱心網友回復:
這具有未定義的行為。typeid允許應用于建構式中正在構造的物件,也是成員初始化器串列,但僅在所有基類子物件的構造完成后。見[class.base.init]/16。
如果typeid(*this)在構建基類之后使用,則[class.cdtor]/5將描述typeid在這種特定情況下的行為。(無論是否是最派生的型別,它都會回傳type_info對應的。)FooFoo
我認為這應該只適用于如果*this具有多型型別,即Foo具有(繼承的)虛擬成員函式(std::exception::what在std::exception::~exception你的情況下)。當前的措辭似乎沒有明確區分這一點,但對于非多型型別,甚至不應該評估運算式,因此*this參考正在構建的物件并不重要。有相關的開放 CWG 問題,例如CWG 問題 1517。
uj5u.com熱心網友回復:
不管 typeid(*this) 的語意如何,另一種方法是將更多的作業轉移到編譯時。具體來說:
- 實作一個 constexpr 函式,它可以讓你得到一個型別的名稱——我的意思是一個正確的名稱,而不是一些煩人的代碼。您可以在這個 SO answer中找到實作。
- 使用繼承 Foo 的類中的型別名稱來構造您的 Foo 基礎。
您可以使用 CRTP 和撰寫進一步自動執行此操作class MyException : Foo<MyException>,Foo模板建構式從其自己的型別別中提取模板引數型別。而這一切都將在編譯時發生!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/517231.html
標籤:C 例外遗产语言律师铿锵
