【发布时间】:2021-12-13 21:15:06
【问题描述】:
我的问题是关于这个小代码 sn-p:
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 != arguments.cend() ? retrieved->second : "" 中的 retrieved->second 被评估为堆栈上的字符串构造,并将 string_view 返回到这很糟糕。
我还可以看到,使用 -O3 编译器将能够内联所有这些、删除分支并完成它......但我希望 -O3 能够完全正确 “好像”我是用 -O0 编译的。
谁能解释为什么编译器会忽略我认为在 -O0 版本中发生的复制构造?
【问题讨论】:
-
对不起,我在代码中重命名了一些东西,可能会扰乱人们的回答流程
-
两个版本都是未定义的行为。返回的 string_view 不拥有字符串数据。它归基础
std::string对象所有。在这两种情况下,当任一函数返回时,它都会超出范围并被销毁,从而为您留下一个已删除对象的 string_view。所有进一步使用它都是未定义的行为,并导致spontaneous demons flying out of everyone's nose。 -
@SamVarshavchik 我认为
get_value_better不是未定义的,因为它为std::string返回了string_view,而std::string仍然存在于my_map中? -
@SamVarshavchik
std::map::find返回的迭代器指向std::map中存在的实际对。get_value_better没有超出范围,完全没问题。