如何让按值返回的函数在堆上分配返回值?C++技术问询
问题解答
关于两个判断的正确性
判断1:C++14中的情况
这个判断是正确的。
在C++14标准中,返回值优化(NRVO/RVO)属于编译器可选实现的优化,而非强制要求。如果returnString()通过手段规避了NRVO,会返回一个临时对象。用这个临时对象构造堆上的T时:
- 若
T的移动构造函数不可用(比如T是不可移动类型、移动构造被显式禁用),编译器只能调用拷贝构造函数创建堆对象,产生额外拷贝开销; - 若能直接在堆内存上构造
T,则可避免这份不必要的开销。
判断2:C++17中的情况
这个判断是正确的。
C++17引入了强制复制消除规则:当纯右值(prvalue)用来初始化同类型对象时,编译器必须直接在目标内存位置构造对象,完全跳过临时对象的创建、移动或拷贝步骤。
对于new T(returnString()),returnString()返回的是T类型的纯右值,编译器会直接在堆分配的内存空间中构造T对象,既不会调用移动构造函数,也不会产生任何拷贝开销——哪怕T没有定义移动构造函数。
泛型类型的更优实现方式
分标准版本讨论:
C++17及以后
new T(returnString())已经是最优实现,强制复制消除会直接在堆上构造对象,无额外开销。如果偏好安全的指针管理,推荐使用std::make_unique<T>(returnString()),效果完全一致且避免裸指针风险。
C++14及更早
在不修改returnString()的前提下,没有完美通用方案,但可做以下优化:
- 优先依赖移动构造:若
T支持移动,编译器会自动将临时对象移动到堆上,开销远低于拷贝; - 使用分配器手动构造:通过
std::allocator分配内存并构造对象,写法如下:
这种写法和void caller() { std::allocator<T> alloc; T* heap_ptr = alloc.allocate(1); try { alloc.construct(heap_ptr, returnString()); // 使用对象逻辑... alloc.destroy(heap_ptr); alloc.deallocate(heap_ptr, 1); } catch (...) { alloc.deallocate(heap_ptr, 1); throw; } }new T(...)性能无差异,但需手动处理异常安全,实际场景中不如直接用new或智能指针便捷。
内容的提问来源于stack exchange,提问作者Chuu
相关产品推荐
相关产品推荐

