返回值是否会有临时被销毁?
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++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++标准。
常量引用会延长临时引用的寿命吗?
- lock_guard是否保护返回值
- 我是否正确测试了返回值优化?
- "co_yield"是否可以在恢复协程时从调用方返回值?
- G++ 编译器是否在未使用返回值的情况下将 constexpr 函数视为常规函数?
- 运算符重载是否真的需要返回值C++?
- 您能否根据是否使用返回值来保证不同的生存期行为?
- 如何检查 range:: 算法(如 find_if)是否返回了值?
- 是否有一些东西限制了未来引入多个返回值C++标准?
- 返回值是否会有临时被销毁?
- 如何避免使用多个if-else来检查返回值是否为错误代码?
- 返回值 vkEnumeratePhysicalDevices 在不同的 VkInstances 之间是否一致?
- 放置 new 的返回值与其操作数的强制转换值之间是否存在(语义)差异
- MMAP是否返回对齐的指针值
- 是否可以检索 C++11 中线程函数的返回值
- std::clamp - 检测函数返回值是否绑定到 const T&
- 是否可以在C 中使回调函数返回值
- 此功能是否具有所有控制路径上的明确返回值
- 是否有一种方法可以通过C 中的OUT参数接收Python中的返回值
- 是否有任何理由将返回值捕获为rvalue参考
- C++标准是否保证函数返回值具有常量地址?