提问人:Dávid Tóth 提问时间:3/7/2023 最后编辑:Peter MortensenDávid Tóth 更新时间:3/14/2023 访问量:1272
是否从临时有效的 C++ 代码中获取引用?
Is taking a reference from a temporary valid C++ code?
问:
我使用了以下语法糖:
for (auto& numberString: {"one", "two", "three", "four"}) { /* ... */}
这是有效的代码吗?AFAIK,基于这个问题,这应该是非法的,但代码按预期运行。我不认为我对此事的理解是正确的。
据我所知,只有文字不应该有内存地址,但链接的问题正在谈论临时和 r 值。
答:
28赞
Jodocus
3/7/2023
#1
是的,此代码有效。
请记住,(对于 C++17),编译器将在语义上用构造替换基于范围的 for 循环
{
auto && __range = {"one", "two", "three", "four"};
for (auto __begin = begin(__range), __end = end(__range); __begin != __end; ++__begin)
{
auto& numberString = *__begin;
/* ... */
}
}
你看,在替换中,生存期延长到最外层范围的生存期。initializer_list
__range
但请注意,如果范围表达式包含临时本身,您仍然很容易导致未定义的行为:
struct some {
auto get_list() { return {"one", "two", "three", "four"}; }
};
some foo() { return some{ }; }
for(auto& numberString : foo().get_list()) { /* ... */ }
上面的代码将导致 <= C++20 中的悬空引用。
只有在 C++23 中,创建的临时的生存期才会延长,从而使其有效。另请参阅 https://en.cppreference.com/w/cpp/language/range-forfoo()
评论
5赞
Miles Budnek
3/8/2023
我很确定您的第二个示例只有在返回对 的成员的引用时才会未定义。按原样返回一个临时对象,该对象一直存在到完整表达式的末尾,该表达式足够长,可以调用它。 返回一个临时对象,然后根据通常的规则延长生存期。get_list
some
foo
some
get_list
get_list
1赞
Sebastian Redl
3/8/2023
实际上,我认为第二个示例即使在 C++20 中也是未定义的。initializer_list 的后备缓冲区是 的本地缓冲区,initializer_list返回值的生存期延长不会改变这一点。(GCC 和 Clang 都警告说,一旦我将返回类型更改为get_list
std::initializer_list<const char*>
)
评论
std::initializer_list