范围内临时对象的寿命是多少?
What's the lifetime of temporary objects in a range-for?
考虑这个 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"};
};
C++ 标准的第 12.2 节指定了临时对象的生命周期。我认为这样可以:
for (auto w : Foo () .words ())
std::cout << w << "\n";
但事实并非如此
~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
这个标准让我很困惑。为什么在循环运行之前调用 ~Foo
?
当前标准在The range-based for statement [stmt.ranged]中说
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
}
}
这意味着您的 Foo().words()
仅用于赋值 auto &&__range = Foo().words();
并且临时对象在代码到达 for 循环之前不会存在。
请注意,我是从 latest C++20 draft 复制的。在 C++11 中,代码有点不同,但相关部分是相同的。
我认为答案可以在 range-for 的定义方式和 __range
的绑定方式中找到。
[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 ...
如果改变for-loop
表达式直接绑定到子对象m_words
(假设是public),那么Foo()
的生命周期会延长以下将起作用
for (auto w : Foo ().m_words)
std::cout << w << "\n";
考虑这个 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"};
};
C++ 标准的第 12.2 节指定了临时对象的生命周期。我认为这样可以:
for (auto w : Foo () .words ())
std::cout << w << "\n";
但事实并非如此
~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
这个标准让我很困惑。为什么在循环运行之前调用 ~Foo
?
当前标准在The range-based for statement [stmt.ranged]中说
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 } }
这意味着您的 Foo().words()
仅用于赋值 auto &&__range = Foo().words();
并且临时对象在代码到达 for 循环之前不会存在。
请注意,我是从 latest C++20 draft 复制的。在 C++11 中,代码有点不同,但相关部分是相同的。
我认为答案可以在 range-for 的定义方式和 __range
的绑定方式中找到。
[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 ...
如果改变for-loop
表达式直接绑定到子对象m_words
(假设是public),那么Foo()
的生命周期会延长以下将起作用
for (auto w : Foo ().m_words)
std::cout << w << "\n";