[英]Infinite loop from access of improperly created variables
為什么這個 go 會進入無限循環,為什么會轉儲 char 0x20?
#include <iostream>
struct Outer {
Outer(std::string &outerString,
std::string &superfluousString1,
std::string &superfluousString2) :
outerString(outerString),
inner(*this) {}
struct Inner {
Inner(Outer &outer) {
std::cout << outer.outerString;
}
} inner;
std::string &outerString;
};
int main() {
std::string
outerString("outerString"),
superfluousString1("superfluousString1"),
superfluousString2("superfluousString2");
Outer outer(outerString, superfluousString1, superfluousString2);
return 0;
}
我發現了這個我正在玩內部類的惠斯特。 C++ 不是主要語言,我是從長期的中斷中來的,所以我問這個是為了提高我的知識。 我知道在正確創建 Outer 之前我不應該使用它,所以這通常是一件非常糟糕的事情。 我覺得真正的答案很可能只是因為我沒有編譯器錯誤並不意味着某些事情是正確的。
一個有趣的旁注是,如果我刪除任何一個多余的字符串,我會得到一個編譯器錯誤,或者它只會出現段錯誤,而這正是我所期望的。 我從我正在玩的一個更復雜的結構中提煉出來,所涉及的元素似乎是引起這種反應所需的最低限度。
我知道在正確創建之前我不應該使用 Outer 的字段
不必要。 您不能在初始化之前使用成員,但可以使用已經初始化的成員來初始化其他成員。 問題是成員是按照聲明的順序初始化的,而不是按照它們出現在初始化列表中的順序。 inner
在outerString
之前聲明,因此它總是先初始化。
我覺得真正的答案很可能只是因為我沒有編譯器錯誤並不意味着某些事情是正確的。
這是正確的,你有未定義的行為,因為你在初始化之前訪問了一個引用( outerString
)。 如果您啟用了警告,您的編譯器應該警告您(請在線查看警告)。
一個有趣的旁注是,如果我刪除任何一個多余的字符串,我會得到一個編譯器錯誤,或者它只會出現段錯誤,而這正是我所期望的。
未定義行為是未定義的,任何事情都可能發生。 對我來說,來自一個編譯器的程序不打印任何內容並正常退出,來自不同編譯器的程序打印大量空格然后崩潰。
您可以通過重新排序您的成員來使其工作(在線查看):
struct Outer {
Outer(std::string &outerString, std::string &superfluousString, std::string &innerString): outerString(outerString), inner(*this) {}
std::string &outerString; //declared before 'inner'
struct Inner {
Inner(Outer &outer) {
std::cout << outer.outerString;
}
} inner;
};
Class成員在class定義內按聲明順序初始化; 不是按照 ctor-initializer 列表中初始化程序的順序。
現代編譯器可以警告這種差異,如果默認情況下沒有發生,您可能需要啟用更多警告。
因此,您的程序在綁定之前確實使用了引用Outer::outerString
,從而導致未定義的行為。
如果在Outer
的 class 定義outerString
的聲明移動到inner
之前,代碼應該定義明確。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.