在C++代码中,从临时对象获取引用是否有效?

huangapple go评论61阅读模式
英文:

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

问题

以下是您要翻译的代码部分:

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

这段代码是否有效?据我所知,根据这个问题,这应该是不合法的,但代码可以正常运行。我认为我对此问题的理解可能是不正确的。

据我所知,只有字面值不应该有内存地址,但链接的问题是在讨论临时值和r-values

英文:

I used the following syntactic sugar:

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

Is this valid code? AFAIK, based on this question, this should be illegal, yet the code runs as expected. I don't think my understanding is correct on the matter.

As far as I know, only literals should not have memory addresses, yet the linked question is talking about temporaries and r-values.

答案1

得分: 28

Yes, this code is valid.

Keep in mind that (for C++17), the compiler will semantically replace the range-based for loop by the construct

{

    auto && __range = {"one", "two", "three", "four"};
    for (auto __begin = begin(__range), __end = end(__range); __begin != __end; ++__begin)
    {

        auto& numberString = *__begin;
        /* ... */
    }

}

You see, the lifetime of the initializer_list is extended to the lifetime of __range inside of the outermost scope in the replacement.

Note, however, that you still can easily cause undefined behavior if the range expression contains a temporary itself:

struct some {
   auto get_list() { return {"one", "two", "three", "four"}; }
};

some foo() { return some{ }; }

for(auto& numberString : foo().get_list()) { /* ... */ }

The above code will result in a dangling reference in <= C++20.
Only in C++23, the lifetime of the temporary created by foo() will get extended such that it becomes valid. See also https://en.cppreference.com/w/cpp/language/range-for

英文:

Yes, this code is valid.

Keep in mind that (for C++17), the compiler will semantically replace the range-based for loop by the construct

{

    auto &amp;&amp; __range = {&quot;one&quot;, &quot;two&quot;, &quot;three&quot;, &quot;four&quot;};
    for (auto __begin = begin(__range), __end = end(__range); __begin != __end; ++__begin)
    {

        auto&amp; numberString = *__begin;
        /* ... */
    }

}

You see, the lifetime of the initializer_list is extended to the lifetime of __range inside of the outermost scope in the replacement.

Note however that you still can easily cause undefined behavior if the range expression contains a temporary itself:

struct some {
   auto get_list() { return {&quot;one&quot;, &quot;two&quot;, &quot;three&quot;, &quot;four&quot;}; }
};

some foo() { return some{ }; }

for(auto&amp; numberString : foo().get_list()) { /* ... */ }

The above code will result in a dangling reference in <= C++20.
Only in C++23, the lifetime of the temporary created by foo() will get extended such that it becomes valid. See also https://en.cppreference.com/w/cpp/language/range-for

huangapple
  • 本文由 发表于 2023年3月7日 15:56:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75659271.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定