是否从临时有效的 C++ 代码中获取引用?

Is taking a reference from a temporary valid C++ code?

提问人:Dávid Tóth 提问时间:3/7/2023 最后编辑:Peter MortensenDávid Tóth 更新时间:3/14/2023 访问量:1272

问:

我使用了以下语法糖:

for (auto& numberString: {"one", "two", "three", "four"}) { /* ... */}

这是有效的代码吗?AFAIK,基于这个问题,这应该是非法的,但代码按预期运行。我不认为我对此事的理解是正确的。

据我所知,只有文字不应该有内存地址,但链接的问题正在谈论临时和 r 值

C++ 参考手册 C++17 临时对象

评论

8赞 Some programmer dude 3/7/2023
临时对象实际上将具有包含循环的生存期,因此它是有效的。std::initializer_list
0赞 Dávid Tóth 3/7/2023
因此,如果我的理解是正确的:只要临时的生存期有效,从中获取引用就是有效的行为。在引用的问题中,与字符串文字没有联系,只有临时的生存期是相关的。我理解正确吗?
5赞 Some programmer dude 3/7/2023
是的,重要的是临时的生命周期。只要临时的生存期长于引用的生存期,一切都很好。

答:

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_listsomefoosomeget_listget_list
1赞 Sebastian Redl 3/8/2023
实际上,我认为第二个示例即使在 C++20 中也是未定义的。initializer_list 的后备缓冲区是 的本地缓冲区,initializer_list返回值的生存期延长不会改变这一点。(GCC 和 Clang 都警告说,一旦我将返回类型更改为get_liststd::initializer_list<const char*>)