C++ NVRO是否适用于对象切片或局部对象成员?如何减少返回值拷贝?
C++ NVRO在对象切片与局部对象成员场景的适用性解答
先明确NVRO(具名返回值优化)的核心适用条件:只有当函数返回的是自身作用域内的自动存储期局部命名对象,且该对象的类型与函数返回类型完全匹配(无切片、无类型转换)时,编译器才会触发NVRO,消除拷贝/移动操作。
针对你提出的两种思路,逐一分析:
思路1:返回局部对象的成员变量
Update buildRecord() { ParserHandler handler; parse(handler); return handler.m_workingUpdate; }
这里返回的handler.m_workingUpdate是ParserHandler对象的成员,并非buildRecord函数直接声明的局部对象。不符合NVRO的触发条件,NVRO不会生效。此时编译器会调用Update的拷贝构造函数(若存在移动构造函数,可能会优化为移动,但这是移动语义,不是NVRO)。
思路2:返回子类对象触发对象切片
Update buildRecord() { ParserHandler handler; parse(handler); return handler; }
这里返回的handler是ParserHandler类型(Update的子类),但函数返回类型是Update,会发生对象切片——仅将handler中的Update基类部分拷贝到返回值中。由于返回对象的类型与函数返回类型不一致(存在继承切片),NVRO同样不会生效,编译器会执行Update的拷贝构造(或移动构造)。
最小化拷贝的优化方案
针对思路1的优化
- 触发移动语义:显式使用
std::move将成员变量转为右值,触发移动构造(前提是Update定义了移动构造函数,若未定义则退化为拷贝):return std::move(handler.m_workingUpdate); - 调整构造位置:如果可以修改
parse接口,让其直接在返回值的内存位置构造Update对象,比如让ParserHandler接受一个Update的引用,在parse中直接初始化该引用:class ParserHandler { public: ParserHandler(Update& target) : m_target(target) {} Update& m_target; }; Update buildRecord() { Update result; ParserHandler handler(result); parse(handler); return result; // 此处可触发NVRO }
针对思路2的优化
- 避免切片+触发移动:如果必须返回
Update类型,显式将子类对象转为右值引用,触发移动构造:return std::move(handler); - 调整返回类型:如果业务允许,将
buildRecord的返回类型改为ParserHandler,此时返回局部对象handler符合NVRO条件,可直接触发优化,后续若需要Update类型,再通过转换处理(但要注意切片风险)。
内容的提问来源于stack exchange,提问作者lano1106
相关产品推荐
相关产品推荐

