gpt4 book ai didi

c++ - auto&& 将如何延长临时对象的生命周期?

转载 作者:可可西里 更新时间:2023-11-01 16:15:38 35 4
gpt4 key购买 nike

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

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

现场观看here .

据说auto&&会延长临时对象的生命周期,但我找不到关于这个规则的标准词,至少在N3690中没有。

最相关的可能是关于临时对象的第 12.2.5 节,但不完全是我要找的。

那么,auto&& 生命周期延长规则会应用于所有表达式中涉及的临时对象,还是仅应用于最终结果?

更具体地说,a.val 是否保证在我们到达情况 1 的范围末尾之前有效(非悬挂)?

编辑:我更新了示例以显示更多案例(3 和 Ex)。

您会看到只有在情况 1 中 O 的生命周期才会延长。

最佳答案

与引用 const 的方式相同:

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

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

或者还有

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?

是的,是的。

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

有关详细信息,请参阅 A Candidate For the “Most Important 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 的,但论点仍然有效:临时对象可以绑定(bind)到对 const 的引用(但不能绑定(bind)到对非 const 的引用).在 C++ 11 中,临时对象可以绑定(bind)到右值引用。在这两种情况下,临时对象的生命周期都会延长到引用的生命周期。

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. The first context is [...]

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

(这些行后面的要点中有一些异常(exception)。)

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

情况 2 中的 O 生命周期短的原因是我们有 auto a = wrapper{O()};(看,没有 & 此处)然后临时文件绑定(bind)到引用。实际上,使用编译器生成的复制构造函数将临时文件复制到 a 中。因此,临时对象的生命周期不会延长,并会在它出现的完整表达式结束时消亡。

这个特定示例中存在危险,因为 wrapper::val 是一个引用。编译器生成的 wrapper 复制构造函数会将 a.val 绑定(bind)到临时对象的 val 成员绑定(bind)到的同一对象。此对象也是一个临时对象,但属于 O 类型。然后,当后者暂时消失时,我们在屏幕上看到 ~O() 并且 a.val 悬垂!

将情况 2 与此进行对比:

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

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

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

现在临时 wrapper 将其 val 成员绑定(bind)到 o。请注意 o 不是临时的。正如我所说,awrapper 临时拷贝,a.val 也绑定(bind)到o。在范围结束之前,临时 wrapper 结束,我们在屏幕上看到第一个 ~wrapper()

然后范围结束,我们得到end-scope。现在,ao 必须以相反的构造顺序销毁,因此我们看到 ~wrapper()a 死了,最后 ~O() 到了 o 的时间。这表明 a.val 没有悬挂。

(最后的评论:我使用了 -fno-elide-constructors 来防止与复制构造相关的优化,这会使这里的讨论复杂化,但这是另一个 story。)

关于c++ - auto&& 将如何延长临时对象的生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19864176/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com