我很好奇這段代碼是否是UB。
https://wandbox.org/permlink/nU0iPLCrPXwQ7Kor
代碼不會崩潰(在 GCC 和 Clang 中,有或沒有優化),這讓我越來越困惑..
#include <list>
#include <vector>
#include <iostream>
#include <utility>
#include <queue>
using namespace std;
int main() {
deque<int> l {1, 2, 3, 4, 5};
vector<reference_wrapper<int>> v (l.begin(), l.end());
// v now holds references to 1, 2, 3, 4, 5 in l
cout << v[3] << '\n'; // 4
l.pop_front(); // 1 popped
for (auto num : l) {
cout << num << ' '; // 2 3 4 5
}
cout << '\n';
cout << v[0] << '\n'; // I think this should crash because 1 is dangling reference
l.pop_front(); // 2 popped
for (auto num : l) {
cout << num << ' '; // 3 4 5
}
cout << '\n';
cout << v[1] << '\n'; // I think it should crash but it still outputs 2
}
uj5u.com熱心網友回復:
您的代碼不會崩潰的原因是您對雙端佇列的實作細節很幸運。
雙端佇列以 512 位元組的塊為單位分配記憶體。雙端佇列中的第一個和最后一個塊可以分別在它們的前面或后面部分填充。指標標記這些位置。只要第一個塊不完全為空,pop_front 只需將該指標向前移動一個元素。
在您的示例中,完整的內容適合一個塊。因此,您只需繼續參考仍然分配的記憶體,并且被雙端佇列認為是空的。當然,任何諸如 push_front 或任何其他調整大小之類的操作都可能會改變這一點。
uj5u.com熱心網友回復:
我很好奇這段代碼是否是UB。
是的,由于使用了懸空參考,這顯然是未定義的行為。
未定義的行為意味著任何事情1都可能發生,包括但不限于給出預期輸出的程式。但永遠不要依賴(或基于)具有未定義行為的程式的輸出。
因此,您看到的輸出是未定義行為的結果。但正如我所說,不要依賴具有 UB 的程式的輸出。該程式可能導致分段錯誤。
使程式正確的第一步是洗掉 UB。只有這樣,您才能開始推理程式的輸出。
1有關未定義行為的更技術上準確的定義,請參見此處提到:對程式的行為沒有限制。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/419345.html
標籤:
