关于返回值临时对象销毁及复制消除新规则的技术问询
嗨,我来帮你理清这两个问题,结合你的代码逐一分析:
首先先把你的代码贴出来方便参考:
#include <iostream> 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}; }
问题一:返回值是否会产生会被销毁的临时对象?
答案是:在C++17及以后的标准下,不会产生额外的临时对象;C++17之前,编译器可以选择优化掉临时对象(大多数主流编译器都会这么做),但不是强制要求。
你的make_foo函数返回的是一个用列表初始化构造的foo<T>纯右值,在C++17的规则中,这种场景属于强制复制消除的范畴——编译器必须直接在调用方的目标内存位置(比如你用auto f = make_foo(...)定义的变量f的内存)构造这个foo<T>对象,不会生成中间临时对象,自然也就不会有额外的析构调用。
你可以自己做个测试:如果写auto f = make_foo(42);,程序只会在f生命周期结束时打印一次destructor,不会有额外的析构输出,这就证明没有临时对象被销毁。
问题二:复制消除的新规则是否适用于当前场景?
完全适用!
C++17对复制消除的规则做了强化,主要针对两种强制消除的场景:
- 返回一个纯右值(比如你的代码里直接构造的
foo<T>{t}); - 返回一个与函数返回类型相同的命名局部对象(这是NRVO,不过C++17里NRVO依然是可选优化,不是强制的,但你的场景不属于这种)。
你的代码恰好命中了第一种强制消除的情况:return {t}本质是构造一个临时的foo<T>纯右值返回,C++17要求编译器直接把这个对象构造在调用方的目标位置,跳过临时对象的创建和销毁过程。
另外补充一点:你提到实际代码里t是lambda,这也不影响——模板参数推导会正确推导出lambda的类型,返回的foo<T>对象依然会被直接构造在调用方的变量中,不会产生临时对象。
内容的提问来源于stack exchange,提问作者463035818_is_not_an_ai
相关产品推荐
相关产品推荐

