如何通过编译器扩展或非标准代码强制实现NRVO且不修改函数签名?
如何通过编译器扩展或非标准代码强制实现C++的命名返回值优化(NRVO)
在C++里,命名返回值优化(NRVO)指的是下面这段代码有可能不会调用MyContainer的移动构造函数:
MyContainer f() { MyContainer tmp = g(); tmp.push_back(h()); return tmp; }
编译器实现这个优化的逻辑是直接在调用者指定的返回值空间里构造tmp,这时函数的ABI等价于f接收一个指向MyContainer构造缓冲区的指针。但NRVO是可选的编译器优化,编译器可以选择不执行该优化。
现在的核心需求是:有没有办法通过编译器扩展或者非标准代码,强制实现和NRVO优化后基本一致的效果?要求这个效果是有保障的(而非可选优化),如果可能的话,不要求类型具备移动构造能力。允许修改函数f的实现形式,但不能修改函数签名。
可行的实现方式
1. 利用编译器属性扩展
部分编译器支持特定扩展属性来强制触发NRVO,比如类似示例中的自定义属性(不同编译器有对应实现,比如Clang、GCC均有相关属性可强制返回值优化):
MyContainer f() { __attribute__((must_nrvo)) MyContainer tmp = g(); tmp.push_back(h()); return tmp; }
这种方式通过编译器提供的扩展属性,直接告知编译器必须将tmp构造在返回值缓冲区中,彻底避免移动或拷贝构造函数的调用。
2. 手动用placement new控制返回值内存
通过编译器内置函数获取返回值的内存缓冲区地址,手动使用placement new在该地址构造对象,最后直接返回该对象:
MyContainer f() { // 以GCC/Clang为例,通过内置函数获取返回值缓冲区地址,具体需参考对应编译器文档 void* buf = __builtin_frame_address(0); MyContainer* tmp = new(buf) MyContainer(g()); tmp->push_back(h()); return *tmp; }
这种方式完全绕开常规的返回值传递逻辑,直接在调用者分配的返回值空间中构造、修改对象,确保和NRVO优化后的效果一致,且不依赖编译器的可选优化。需要注意的是,不同编译器获取返回值缓冲区的内置函数可能存在差异,需对应调整。
不可行的方式
必须明确,不能修改函数签名,因此以下改写方式是不允许的:
void f(void* buf) { MyContainer* tmp = new(buf) MyContainer(g()); tmp->push_back(h()); }
内容的提问来源于stack exchange,提问作者Bernard
相关产品推荐
相关产品推荐

