我的問題與這個小代碼片段有關:
typedef std::map<std::string, std::string> my_map_t;
std::string_view get_value_worse(const my_map_t& input_map, std::string_view value)
{
auto retrieved = input_map.find(value.data());
return retrieved != input_map.cend() ? retrieved->second : "";
}
std::string_view get_value_better(const my_map_t& input_map, std::string_view value)
{
auto retrieved = input_map.find(value.data());
if (retrieved != input_map.cend())
{
return retrieved->second;
}
return "";
}
int main()
{
my_map_t my_map = {
{"key_0", "value_0"},
{"key_1", "value_1"},
};
std::cout << (get_value_worse(my_map, "key_0") == get_value_better(my_map, "key_0")) << std::endl;
}
在沒有優化的最新 gcc 下,這會列印0為 false,而在 -O3 下,這會列印1為 true。
我相信未優化的行為是因為第二個和第三個比較運算子引數是運算式,而不是陳述句 - 因此retrieved->secondinretrieved != arguments.cend() ? retrieved->second : ""被評估為堆疊上的字串構造,并且回傳一個 string_view 是不好的。
我還可以看到,使用 -O3 編譯器將能夠行內所有這些,洗掉分支并完成它......但我希望 -O3完全“就像”我用 -O0 編譯.
誰能解釋為什么編譯器要省略我認為在 -O0 版本中發生的復制構造?
uj5u.com熱心網友回復:
在條件運算式中,std::string構造了一個臨時物件。臨時物件通常在堆疊上構造,盡管這是一個不重要的實作細節。重要的是臨時物件在return陳述句結束時被銷毀,所以回傳的std::string_view是dangling。嘗試訪問它指向的資料(使用==運算子或其他方式)會導致未定義的行為。
當程式包含未定義的行為時,編譯器可以對它做任何想做的事情。特別是,允許??編譯器通過假設暗示未定義行為的條件始終為假來進行優化。如果事實證明這個假設是錯誤的,那么編譯器就會擺脫困境(因為這意味著發生了未定義的行為)。您的編譯器究竟做了什么樣的假設尚不清楚。這也無關緊要,因為您不能依賴于您現在看到的行為。您應該重寫您的程式以洗掉未定義的行為。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/340743.html
下一篇:“解包”宏引數
