会不会有一个临时的被销毁的返回值?

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

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

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++17 起保证没有临时的。

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

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

在 C++11 中,即使是无名的临时复制省略也只是允许而不是强制的。它在此处描述 copy elision。自 C++17 起强制执行。

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

并且您可以测试您的编译器,因为大多数现代编译器都会在此处省略复制。

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

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

在此函数中,return 对象将不会在该函数的范围内构造。它将在范围外创建 临时未命名对象。 如果您将 return 值绑定到 新命名对象 将调用移动构造函数(如果未定义移动则复制)以创建您 新对象 来自 return 临时 。但是,如果您将 returned temporary 绑定到 const reference 它将严格绑定到该引用,并且不会构造新对象并且在该引用结束之前不会破坏 temporary的范围。

编辑: 为了不误导你。在函数范围内调用的临时构造函数,但该临时函数的生命周期确实会延长到 const 引用的生命周期

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

Does a const reference prolong the life of a temporary?