简体   繁体   English

如何自动延长临时对象的寿命?

[英]How would auto&& extend the life-time of the temporary object?

The code below illustrated my concern: 下面的代码说明了我的担忧:

#include <iostream>


struct O
{
    ~O()
    {
        std::cout << "~O()\n";
    }
};

struct wrapper
{
    O const& val;

    ~wrapper()
    {
        std::cout << "~wrapper()\n";
    }
};

struct wrapperEx // with explicit ctor
{
    O const& val;

    explicit wrapperEx(O const& val)
      : val(val)
    {}

    ~wrapperEx()
    {
        std::cout << "~wrapperEx()\n";
    }
};

template<class T>
T&& f(T&& t)
{
    return std::forward<T>(t);
}


int main()
{
    std::cout << "case 1-----------\n";
    {
        auto&& a = wrapper{O()};
        std::cout << "end-scope\n";
    }
    std::cout << "case 2-----------\n";
    {
        auto a = wrapper{O()};
        std::cout << "end-scope\n";
    }
    std::cout << "case 3-----------\n";
    {
        auto&& a = wrapper{f(O())};
        std::cout << "end-scope\n";
    }
    std::cout << "case Ex-----------\n";
    {
        auto&& a = wrapperEx{O()};
        std::cout << "end-scope\n";
    }
    return 0;
}

See it live here . 看到它住在这里

It's said that auto&& will extend the life-time of the temporary object, but I can't find the standard words on this rule, at least not in N3690. 据说auto&&会延长临时对象的寿命,但我找不到此规则的标准字词,至少在N3690中找不到。

The most relevant may be section 12.2.5 about temporary object, but not exactly what I'm looking for. 最相关的可能是关于临时对象的12.2.5节,但不完全是我要寻找的对象。

So, would auto&& life-time extension rule apply to all the temporary objects involved in the expression, or only the final result? 那么,auto &&生命周期扩展规则是适用于表达式中涉及的所有临时对象还是仅适用于最终结果?

More specific, is a.val guaranteed to be valid (non-dangling) before we reach the end-of-scope in case 1? 更具体地说,在情况1到达作用域末端之前, a.val保证有效(非悬挂)?

Edit: I updated the example to show more cases (3 & Ex). 编辑:我更新了示例以显示更多案例(3和Ex)。

You'll see that only in case 1 the lifetime of O is extended. 您将看到只有在情况1中,O的寿命才会延长。

In the same way that a reference to const does: 引用const方式相同:

const auto& a = wrapper{O()};

or 要么

const wrapper& a = wrapper{O()};

or also 或者也

wrapper&& a = wrapper{O()};

More specific, is a.val guaranteed to be valid (non-dangling) before we reach the end-of-scope in case 1? 更具体地说,在情况1到达作用域末端之前, a.val保证有效(非悬挂)?

Yes, it is. 是的。

There's (almost) nothing particularly important about auto here. 这里的auto几乎没有什么特别重要的。 It's just a place holder for the correct type ( wrapper ) which is deduced by the compiler. 它只是由编译器推断出的正确类型( wrapper )的占位符 The main point is the fact that the temporary is bound to a reference. 要点是,临时对象绑定到引用。

For more details see A Candidate For the “Most Important const” which I quote: 有关更多详细信息,请参见我引用的“最重要const”候选人

Normally, a temporary object lasts only until the end of the full expression in which it appears. 通常,临时对象仅持续到其出现的完整表达式的结尾。 However, C++ deliberately specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself 但是,C ++故意指定将临时对象绑定到堆栈上const的引用会延长临时对象的寿命至引用本身的寿命

The article is about C++ 03 but the argument is still valid: a temporary can be bound to a reference to const (but not to a reference to non- const ). 本文是关于C ++ 03的,但该参数仍然有效:可以将临时绑定到对const的引用(但不能绑定到对non- const的引用)。 In C++ 11, a temporary can also be bound to an rvalue reference. 在C ++ 11中,临时变量可以绑定到右值引用。 In both cases, the lifetime of the temporary is extended to the lifetime of the reference. 在这两种情况下,临时项的寿命都延长到参考的寿命。

The relevant parts of the C++11 Standard are exactly those referred in the OP, that is, 12.2 p4 and p5: C ++ 11标准的相关部分正是OP中提到的部分,即12.2 p4和p5:

4 - There are two contexts in which temporaries are destroyed at a different point than the end of the full expression. 4-在两种情况下,临时变量在与完整表达式末尾不同的位置被销毁。 The first context is [...] 第一个上下文是[...]

5 - The second context is when a reference is bound to a temporary. 5-第二种情况是引用绑定到临时项时。 [...] [...]

(There are some exceptions in the bullet points following these lines.) (这些行后面的项目符号中有一些例外。)

Update : (Following texasbruce's comment.) 更新 :(根据texasbruce的评论。)

The reason why the O in case 2 has a short lifespan is that we have auto a = wrapper{O()}; 情况2中的O寿命短的原因是我们有auto a = wrapper{O()}; (see, there's no & here) and then the temporary is not bound to a reference. (请参见,此处没有& ),然后该临时对象就不会绑定到引用。 The temporary is, actually, copied into a using the compiler generated copy-constructor. 实际上,临时文件是使用编译器生成的copy-constructor复制到a Therefore, the temporary doesn't have its lifetime expanded and dies at the end of the full expression in which it appears. 因此,临时项不会延长其生存期,并且会在出现的完整表达式的末尾死亡。

There's a danger in this particular example because wrapper::val is a reference. 在此特定示例中存在危险,因为wrapper::val是引用。 The compiler generated copy-constructor of wrapper will bind a.val to the same object that the temporary's val member is bound to. 编译器生成的wrapper copy-constructor会将a.val绑定到与临时val成员绑定到的同一对象。 This object is also a temporary but of type O . 该对象也是临时的,但类型为O Then, when this latter temporary dies we see ~O() on the screen and a.val dangles! 然后,当后一个临时对象死亡时,我们在屏幕上看到a.val ~O() ,并且a.val悬挂了!

Contrast case 2 with this: 与此进行对比的情况2:

std::cout << "case 3-----------\n";
{
    O o;
    auto a = wrapper{o};
    std::cout << "end-scope\n";
}

The output is (when compiled with gcc using option -fno-elide-constructors ) 输出是(当使用gcc使用选项-fno-elide-constructors编译时)

case 3-----------
~wrapper()
end-scope
~wrapper()
~O()

Now the temporary wrapper has its val member bound to o . 现在,临时wrapper将其val成员绑定到o Notice that o is not a temporary. 请注意, o不是临时的。 As I said, a is a copy of the wrapper temporary and a.val also binds to o . 如我所说, awrapper临时文件的副本,而a.val也绑定到o Before the scope ends the temporary wrapper dies and we see the first ~wrapper() on the screen. 在作用域结束之前,临时wrapper死亡,我们在屏幕上看到第一个~wrapper()

Then the scope ends and we get end-scope . 然后范围结束,我们得到end-scope Now, a and o must be destroyed in the reverse order of construction, hence we see ~wrapper() when a dies and finally ~O() when it's o 's time. 现在, ao必须在施工相反的顺序被破坏,因此,我们看到~wrapper()时, a模具和最后~O()时,它的o的时间。 This shows that a.val doesn't dangle. 这表明a.val不会a.val

(Final remark: I've used -fno-elide-constructors to prevent a optimization related to copy-construction that would complicate the discussion here but this is another story .) (最后再说一句:我已经使用-fno-elide-constructors ,防止复制建设,将这里的讨论复杂化相关的一个优化但这是另一个故事 。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 参考成员绑定到临时 object,其生命周期将短于构造的 object 的生命周期 - Reference member binds to a temporary object whose life-time would be shorter than the lifetime of the constructed object “auto&amp;&amp; a= f();”中的 a 的生命周期是多少其中 f() 按值返回 object? - What is the life time of a in "auto&& a= f();" where f() returns an object by value? 在&#39;for&#39;语句的第二个“参数”中声明的对象的生命周期 - Life-time of object declared in the second “parameter” of 'for' statement c ++,匿名(未命名)变量的对象生命周期 - c++, object life-time of anonymous (unnamed) variables 数据成员和右值生存期 - Data member and rvalue life-time 引用未命名的临时对象(生命期) - Reference to an unnamed temporary object (life time) 如何在一般的lambda中完美地转发`auto &amp;&amp;`? - How to perfectly forward `auto&&` in a generic lambda? C ++临时对象成员函数的生存时间 - C++ temporary object member function life time 为什么 const 引用不能延长通过函数传递的临时对象的寿命? - Why doesn't a const reference extend the life of a temporary object passed via a function? 什么时候不使用`auto &amp;&amp;`? - When not to use `auto&&`?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM