另一个c++临时生命周期混淆

Another c++ temporary lifetime confusion

本文关键字:周期 生命 c++ 另一个      更新时间:2023-10-16

在下面的代码片段中…在ToXML::s_成员变量中存储Quote::toXML返回的临时字符串的引用是否安全,至少只要它仅与<<操作符一起使用?即子表达式q.toXML的结果是否存活到下一个; ?

这里的完整表达式是什么,除了q.toXML的返回值。整个std::cout还是对ToXML构造函数的调用?

#include <iostream>
#include <string>
struct ToXML
{
    ToXML(char const * const tag, std::string const & s) : tag_(tag), s_(s)
    {
    }
    char const * tag_;
    std::string const & s_;
};
std::ostream & operator << (std::ostream & os, ToXML const & v)
{
    return os << "<" << v.tag_ << ">" << v.s_ << "</" << v.tag_ << ">";
}
struct Quote
{
    std::string toXML() const
    {
        return "<Quote/>";
    }
};
int main()
{
    Quote q;
    std::cout << ToXML("quote", q.toXML()) << std::endl;
    return 0;
}

是的,它是安全的。

从[class.temp]:

在两种上下文中,临时变量在与完整表达式末尾不同的位置被销毁。[…]

第二个上下文是当引用绑定到临时对象时引用所指向的临时对象绑定的或临时的,它是引用被绑定到的子对象的完整对象在引用的生命周期内,除了:
—在函数调用(5.2.2)中绑定到引用形参的临时对象将一直持续到函数调用完成

我们在那个要点上。临时对象被绑定到一个引用形参(s),并一直存在,直到包含调用的完整表达式完成为止。也就是说,它一直持续到

std::cout << ToXML("quote", q.toXML()) << std::endl;
// --- here ---------------------------------------^

由于它在整个使用过程中持续使用,因此是完全安全的。但是,一旦您执行如下操作:

ToXML x("quote", q.toXML());

你被悬空引用困住了,所以我会谨慎地使用这个模式。