Consider this class:
class Foo
{
public:
~ Foo ()
{
std::cout << "~Foo\n";
}
typedef std::vector<std::string> Words;
const Words & words ()
{
return m_words;
}
private:
Words m_words = {"foo", "bar", "baz"};
};
Section 12.2 of the C++ standard specifies lifetimes of temporary objects. I thought this would be okay:
for (auto w : Foo () .words ())
std::cout << w << "\n";
But it wasn't
~Foo
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
[1] 10290 abort (core dumped) ./a.out
The standard is confusing me. Why is ~Foo
being called before the loop runs?
The current standard says in The range-based for statement [stmt.ranged] that
The range-based for statement
for ( init-statementopt for-range-declaration : for-range-initializer )
statement
is equivalent to{ init-statementopt auto &&__range = for-range-initializer ; auto __begin = begin-expr ; auto __end = end-expr ; for ( ; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }
This means that your Foo().words()
is only used in the assignment auto &&__range = Foo().words();
and that the temporary object not lives until the code reaches the for loop.
Please note that I copied from the latest C++20 draft . In C++11 the code is a bit different, but the relevant part is the same.
I think that the answer is to be found in the way the range-for is defined and to what __range
is bound to.
[class.temporary]/6 - There are three contexts in which temporaries are destroyed at a different point than the end of the full-expression.
- The third context is when a reference is bound to a temporary object. The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference ...
If you change the for-loop
expression to bind directly to the subobject m_words
(assuming that it were public), then the lifetime of Foo()
will be extended and the following will work
for (auto w : Foo ().m_words)
std::cout << w << "\n";
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.