C++ NRVO
NRVO(Named Return Value Optimization,具名返回值优化)是 C++ 中一种编译器优化技术,旨在消除函数返回对象时产生的临时对象和多余的拷贝操作。它是 RVO(Return Value Optimization,返回值优化)的一种特例,专门处理返回"具名变量"(即有名字的局部变量)的场景。
为什么需要 NRVO?
先看一个没有 NRVO 时的场景:
class MyClass { public: MyClass() { std::cout << "Constructor\n"; } MyClass(const MyClass&) { std::cout << "Copy Constructor\n"; } ~MyClass() { std::cout << "Destructor\n"; } }; MyClass createObject() { MyClass obj; // 具名局部变量 return obj; // 理论上:创建临时对象 + 两次析构 } int main() { MyClass a = createObject(); }没有 NRVO 时的理想化步骤(假设编译器不做任何优化):
createObject()内部构造obj(调用构造函数)return obj时,用obj拷贝构造一个临时对象(调用拷贝构造函数)createObject()结束时,obj析构(调用析构函数)用临时对象拷贝构造
a(调用拷贝构造函数)临时对象析构(调用析构函数)
输出可能类似:
Constructor // obj 构造 Copy Constructor // obj → 临时对象 Destructor // obj 析构 Copy Constructor // 临时对象 → a Destructor // 临时对象析构NRVO 如何工作?
启用 NRVO 后,编译器会直接在函数外部预先分配的空间上构造对象,跳过中间所有拷贝步骤。
NRVO 优化后的步骤:
编译器在函数调用前,就在
main的栈帧上为a预留空间将这个空间的地址"偷偷"传给
createObject()createObject()直接在传入的地址上构造obj(此时obj和a其实是同一个地址)直接把
obj当作返回值使用,无需拷贝函数结束时也无需析构
obj(因为它就是a本身)
输出变为:
Constructor // 直接在 a 的地址上构造关键机制:编译器会把函数签名从MyClass createObject()在底层改写成类似void createObject(MyClass* this_ptr)的形式,让函数直接在目标位置构造对象。
代码示例对比
// 示例 1:NRVO 生效 MyClass createObject() { MyClass obj; // 具名变量 return obj; // NRVO:直接优化掉拷贝 } // 示例 2:RVO 生效(匿名临时对象) MyClass createObject() { return MyClass(); // RVO:构造临时对象直接作为返回值 } // 示例 3:NRVO 失效的情况 MyClass createObject(bool condition) { MyClass obj1; MyClass obj2; return condition ? obj1 : obj2; // 编译器无法确定返回哪个,NRVO 失效 }