返回值是否会有临时被销毁?

Will there be a temporary for the returned value that gets destroyed?

本文关键字:是否 返回值      更新时间:2023-10-16

我对有关复制省略的新规则有点困惑,实际上我什至不确定它是否适用于这种情况。我有这个:

template <typename T> struct foo {
T t;
foo(const T& t) : t(t) {}
~foo() { std::cout << "destructor n"; }
}
template <typename T> foo<T> make_foo(const T& t) { return {t}; }

其中make_foo只是允许推断参数(在实际代码中t是一个 lambda,但为了简单起见,或者更确切地说是为了混淆,我很抱歉)如

auto x = make_foo(123);

现在我需要绝对确定foo析构函数只调用一次:当x超出范围时。恐怕这是一个不清楚你在问什么的问题,但如果很明显不会有任何临时foo,那将足够;)答案。

在C++11中,我能确定make_foo不会有临时foo被摧毁吗?仅当析构函数超出范围时,才应调用x

正如评论中正确指出的那样,这个问题是 XY 问题的 Y 部分,X 部分是我想实现一些范围的结束功能。foo的析构函数有一些副作用(在示例中为cout),应该在x范围的末尾调用,但不要在make_foo中调用,以防有一些临时foo

在 C++11 中,即使对于无名临时也只允许不强制复制省略。这里描述的是复制省略。它自C++17年开始强制执行。

同样在 C++17 中,您将拥有自动扣除指南,因此您将不需要这样的结构。

你可以测试你的编译器,因为大多数现代编译器都会在这里省略复制。

自 C++17 以来,保证没有临时的。

在 C++14 及更早版本中,必须有一个可访问的 copy/move 构造函数,并且无论是否实际存在临时构造函数,编译器都是可选的。

据我所知,唯一实际显示临时的编译器是调试模式下的旧版本的MSVC。

在您的情况下,为了确保不会为未命名的对象调用析构函数,您可以将返回值绑定到const 引用。 为了澄清如果我们不依赖复制省略会发生什么:

template <typename T> foo<T> make_foo(const T& t) { return {t}; }

在此函数中,返回对象不会在该函数的范围内构造。它将在范围之外创建临时未命名对象。 如果要将返回值绑定到新的命名对象,则将调用移动构造函数(如果未定义移动,则复制)以从返回的临时对象创建新对象。但是,如果将返回的临时绑定到const引用,它将严格绑定到该引用,并且不会构造新对象,并且在该引用超出范围之前不会破坏临时对象。

编辑: 为了不误导你。在函数作用域中调用的临时构造函数,但该临时的生存期确实会延长到 const 引用的生存期

如果您需要更多信息,可以查看此答案。它指的是C++标准。

常量引用会延长临时引用的寿命吗?