优化之间的 C++ 程序行为不同
C++ program behaviour different between optimizations
我的问题与这个小代码片段有关:
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
为假,而在 -O3 下打印 1
为真。
我认为未优化的行为是因为第二个和第三个比较运算符参数是表达式,而不是语句 - 因此 retrieved != arguments.cend() ? retrieved->second : ""
中的 retrieved->second
在堆栈上被评估为字符串构造, 并返回 string_view 是不好的。
我还可以看到,使用 -O3,编译器将能够内联所有这些,删除分支,并完成它...但我希望 -O3 能够准确地执行 “好像”我用 -O0 编译了。
任何人都可以解释为什么编译器会省略我认为在 -O0 版本中发生的复制构造吗?
在条件表达式中,构造了一个临时的std::string
对象。临时对象通常构建在 堆栈 上,尽管这是一个不重要的实现细节。重要的是临时对象在 return
语句结束时被销毁,所以返回的 std::string_view
是悬空的。尝试访问它指向的数据(使用 ==
运算符或其他方式)会导致未定义的行为。
当程序包含未定义的行为时,编译器可以为所欲为。特别是,允许编译器通过假设暗示未定义行为的条件始终为假来进行优化。如果事实证明这个假设是 错误的 ,那么编译器就可以摆脱困境(因为这意味着发生了未定义的行为)。您的编译器究竟做出了什么样的假设尚不清楚。这也并不重要,因为您不能依赖于您现在看到的行为。您应该重写您的程序以删除未定义的行为。
我的问题与这个小代码片段有关:
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
为假,而在 -O3 下打印 1
为真。
我认为未优化的行为是因为第二个和第三个比较运算符参数是表达式,而不是语句 - 因此 retrieved != arguments.cend() ? retrieved->second : ""
中的 retrieved->second
在堆栈上被评估为字符串构造, 并返回 string_view 是不好的。
我还可以看到,使用 -O3,编译器将能够内联所有这些,删除分支,并完成它...但我希望 -O3 能够准确地执行 “好像”我用 -O0 编译了。
任何人都可以解释为什么编译器会省略我认为在 -O0 版本中发生的复制构造吗?
在条件表达式中,构造了一个临时的std::string
对象。临时对象通常构建在 堆栈 上,尽管这是一个不重要的实现细节。重要的是临时对象在 return
语句结束时被销毁,所以返回的 std::string_view
是悬空的。尝试访问它指向的数据(使用 ==
运算符或其他方式)会导致未定义的行为。
当程序包含未定义的行为时,编译器可以为所欲为。特别是,允许编译器通过假设暗示未定义行为的条件始终为假来进行优化。如果事实证明这个假设是 错误的 ,那么编译器就可以摆脱困境(因为这意味着发生了未定义的行为)。您的编译器究竟做出了什么样的假设尚不清楚。这也并不重要,因为您不能依赖于您现在看到的行为。您应该重写您的程序以删除未定义的行为。