范围内临时对象的生存期是多少?
What's the lifetime of temporary objects in a range-for?
考虑这个类:
class Foo
{
public:
~ Foo ()
{
std::cout << "~Foon";
}
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
?
当前标准在 基于范围的 for 语句 [stmt.ranged] 中说
基于范围的 for 语句
for ( init-statementopt for-range-declaration : for-range-initializer )
声明
相当于{ 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 循环之前,临时对象不会存在。
请注意,我是从最新的 C++20 草案中复制的。在 C++11 中,代码有点不同,但相关部分是相同的。
我认为答案可以在定义范围的方式以及__range
绑定的内容中找到。
[class.temporary]/6 - 在三种上下文中,临时在与完整表达式结束不同的点被销毁。
- 第三个上下文是当引用绑定到临时对象时。引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生存期内保持不变......
如果将for-loop
表达式更改为直接绑定到子对象m_words
(假设它是公共的),则Foo()
的生存期将延长,并且以下内容将起作用
for (auto w : Foo ().m_words)
std::cout << w << "n";
相关文章:
- GCC对可能有效的代码抛出init list生存期警告
- 在不复制临时对象的情况下延长其生存期
- 结束另一个线程中使用的对象的生存期
- "this"指针的值在对象的生存期内是否恒定?
- 创建具有全局生存期的 UObject
- C++17 和静态临时生存期的参考扩展
- 数组对象的生存期是否在重用其元素存储时结束?
- 共享指针生存期
- 具有空洞初始化的对象的生存期
- 如何在向量列表初始化时避免对象复制以及如何延长临时的生存期
- 指针引用的生存期(以 C++为单位)
- 子表达式中临时对象的生存期
- 临时实例的生存期是多少
- thread_local 和 std::future 对象 - 对象的生存期是多少
- 范围内临时对象的生存期是多少?
- 作为参数立即传递的对象生存期是多少
- 临时绑定到引用参数的默认参数的生存期是多少
- 块内变量的生存期是多少
- 单例类的成员变量的生存期是多少?
- std::string::c_str()的结果的生存期是多少