C++中临时的保证寿命?

Mar*_*som 95 c++

C++是否为在函数调用中创建但未用作参数的临时变量的生命周期提供保证?这是一个示例类:

class StringBuffer
{
public:
    StringBuffer(std::string & str) : m_str(str)
    {
        m_buffer.push_back(0);
    }
    ~StringBuffer()
    {
        m_str = &m_buffer[0];
    }
    char * Size(int maxlength)
    {
        m_buffer.resize(maxlength + 1, 0);
        return &m_buffer[0];
    }
private:
    std::string & m_str;
    std::vector<char> m_buffer;
};
Run Code Online (Sandbox Code Playgroud)

以下是您将如何使用它:

// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);

std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
Run Code Online (Sandbox Code Playgroud)

什么时候会调用临时StringBuffer对象的析构函数?是吗:

  • 在调用GetString之前?
  • GetString返回后?
  • 编译器依赖?

我知道C++保证本地临时变量只要有引用就有效 - 当引用成员变量时,它是否适用于父对象?

谢谢.

Joh*_*itb 103

在完整表达式结束时调用那种临时数的析构函数.这是最外层的表达,不是任何其他表达的一部分.在您的情况下,在函数返回并评估值之后.所以,它会很好用.

事实上,正是使表达模板起作用的原因:它们可以在表达式中保持对那种临时表的引用

e = a + b * c / d
Run Code Online (Sandbox Code Playgroud)

因为每个临时都会持续到表达式

x = y
Run Code Online (Sandbox Code Playgroud)

完全评估.它12.2 Temporary objects在标准中非常简洁地描述.

  • @JohannesSchaub:在这种情况下什么是“完整表达式”:`printf("%s", strdup(std::string("$$$").c_str()));`?我的意思是如果`strdup (std::string("$$$").c_str())` 作为完整的表达式,那么`strdup` 看到的指针就是*valid*。如果`std::string("$$$").c_str()` 是一个完整的表达式,那么`strdup` 看到的指针就是*无效*!你能不能根据这个例子再解释一下? (3认同)
  • 我从来没有得到一份标准副本.我应该把它作为优先事项. (2认同)
  • @GrimFandango AIUI您的整个`printf`就是完整的表达。因此,`strdup`是不必要的内存泄漏-您可以让它直接打印`c_str()`。 (2认同)
  • “那种临时工”——那是什么?我如何判断我的临时性是否是“那种”临时性? (2认同)

Ric*_*ick 16

litb的回答很准确.临时对象的生命周期(也称为rvalue)与表达式相关联,并且在完整表达式的末尾调用临时对象的析构函数,并且当调用StringBuffer上的析构函数时,m_buffer上的析构函数也将是调用,但不是m_str上的析构函数,因为它是一个引用.

请注意,C++ 0x稍微改变了一些东西,因为它添加了rvalue引用并移动了语义.基本上通过使用rvalue引用参数(用&&表示),我可以将rvalue"移动"到函数中(而不是复制它),并且rvalue的生命周期可以绑定到它移动到的对象,而不是表达式.MSVC团队有一篇非常好的博客文章,详细介绍了这一点,我鼓励大家阅读.

移动右值的教学示例是临时字符串,我将在构造函数中显示赋值.如果我有一个包含字符串成员变量的类MyType,可以在构造函数中使用rvalue初始化它,如下所示:

class MyType{
   const std::string m_name;
public:
   MyType(const std::string&& name):m_name(name){};
}
Run Code Online (Sandbox Code Playgroud)

这很好,因为当我使用临时对象声明此类的实例时:

void foo(){
    MyType instance("hello");
}
Run Code Online (Sandbox Code Playgroud)

发生的事情是我们避免复制和销毁临时对象,并且"hello"直接放在拥有类实例的成员变量中.如果对象的重量比"字符串"重,则额外的复制和析构函数调用可能很重要.

  • 为了使移动工作,我认为你需要删除 const 并使用 std::move 像 MyType(std::string&amp;&amp; name) : m_name(std::move(name)) {} (2认同)