如何自动&&延长临时对象的寿命? [英] How would auto&& extend the life-time of the temporary object?

查看:101
本文介绍了如何自动&&延长临时对象的寿命?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码说明了我的担忧:

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;
}

此处.

据说auto&&会延长临时对象的寿命,但我找不到此规则的标准字词,至少在N3690中找不到.

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.

最相关的可能是有关临时对象的12.2.5节,但不完全是我要找的东西.

The most relevant may be section 12.2.5 about temporary object, but not exactly what I'm looking for.

因此,自动&&生命周期扩展规则适用于 all 表达式中涉及的临时对象,还是仅适用于最终结果?

So, would auto&& life-time extension rule apply to all the temporary objects involved in the expression, or only the final result?

更具体地讲,在情况1到达范围的尽头之前,a.val是否保证有效(无悬挂)?

More specific, is a.val guaranteed to be valid (non-dangling) before we reach the end-of-scope in case 1?

修改: 我更新了示例,以显示更多案例(3及以上).

I updated the example to show more cases (3 & Ex).

您会看到,只有在情况1中,O的寿命才会延长.

You'll see that only in case 1 the lifetime of O is extended.

推荐答案

与对const的引用相同:

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

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

或者也是

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

更具体地讲,在情况1到达范围的尽头之前,a.val是否保证有效(无悬挂)?

More specific, is a.val guaranteed to be valid (non-dangling) before we reach the end-of-scope in case 1?

是的.

这里auto几乎没有什么特别重要的.它只是由编译器推断出的正确类型(wrapper)的占位符.要点是,临时对象绑定到引用.

There's (almost) nothing particularly important about auto here. It's just a place holder for the correct type (wrapper) which is deduced by the compiler. 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:

通常,临时对象仅持续到出现它的完整表达式的末尾.但是,C ++故意指定将临时对象绑定到堆栈上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 ++ 03的,但该参数仍然有效:可以将临时绑定到对const的引用(但不能绑定到对非const的引用).在C ++ 11中,也可以将临时绑定到右值引用.在这两种情况下,临时项的生存期都会延长到引用的生存期.

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). In C++ 11, a temporary can also be bound to an rvalue reference. In both cases, the lifetime of the temporary is extended to the lifetime of the reference.

C ++ 11标准的相关部分正是OP中提到的部分,即12.2 p4和p5:

The relevant parts of the C++11 Standard are exactly those referred in the OP, that is, 12.2 p4 and p5:

4-在两种情况下,临时节点会被销毁 不同于完整表达的结尾.第一个背景 是[...]

4 - There are two contexts in which temporaries are destroyed at a different point than the end of the full expression. The first context is [...]

5-第二种情况是引用绑定到临时项时. [...]

5 - The second context is when a reference is bound to a temporary. [...]

(这些行后面的项目符号中有一些例外.)

(There are some exceptions in the bullet points following these lines.)

更新 :(根据texasbruce的评论.)

Update: (Following texasbruce's comment.)

第2种情况下O寿命短的原因是我们有auto a = wrapper{O()};(请参见此处没有&),然后临时 not 绑定到了参考.实际上,使用编译器生成的copy-constructor将临时副本复制到a中.因此,临时对象的生存期不会延长,并且会在其出现的完整表达式的结尾处死亡.

The reason why the O in case 2 has a short lifespan is that we have 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. Therefore, the temporary doesn't have its lifetime expanded and dies at the end of the full expression in which it appears.

在此特定示例中存在危险,因为wrapper::val是参考.编译器生成的wrapper的复制构造函数会将a.val绑定到与临时val成员绑定到的对象相同的对象.该对象也是临时的,但类型为O.然后,当后一个临时对象死亡时,我们在屏幕上看到~O()并悬挂了a.val

There's a danger in this particular example because wrapper::val is a reference. The compiler generated copy-constructor of wrapper will bind a.val to the same object that the temporary's val member is bound to. This object is also a temporary but of type O. Then, when this latter temporary dies we see ~O() on the screen and a.val dangles!

与案例2进行对比:

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

输出为(当使用gcc使用选项-fno-elide-constructors进行编译时)

The output is (when compiled with gcc using option -fno-elide-constructors)

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

现在,临时wrapperval成员已绑定到o.请注意,o不是临时的.如我所说,awrapper临时副本,而a.val也绑定到 o.在示波器结束之前,临时wrapper死亡,我们在屏幕上看到第一个~wrapper().

Now the temporary wrapper has its val member bound to o. Notice that o is not a temporary. As I said, a is a copy of the wrapper temporary and a.val also binds to o. Before the scope ends the temporary wrapper dies and we see the first ~wrapper() on the screen.

然后范围结束,我们得到end-scope.现在,必须按相反的顺序销毁ao,因此,当a死亡时,我们会看到~wrapper(),而到了o的时间,最终会看到~O().这表明a.val不会悬空.

Then the scope ends and we get 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. This shows that a.val doesn't dangle.

(最后一点:我已经使用-fno-elide-constructors来防止与复制构造相关的优化,这会使此处的讨论复杂化,但这是另一个

(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.)

这篇关于如何自动&amp;&amp;延长临时对象的寿命?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆