为何按值传递的参数作为按值返回值时无法进行复制消除?
为什么返回按值传递的参数时无法实现复制消除
复制消除(比如命名返回值优化NRVO)的核心前提是:编译器能控制返回对象的内存地址,让它直接在调用方预留的返回值位置构造,以此跳过拷贝操作。但按值传递的参数不满足这个条件:
- 按值传递的参数
s,它的内存是在当前函数的栈帧里分配的——准确说是调用方发起函数调用时,就已经把实参拷贝到了这个固定位置,这个地址在函数执行前就确定好了。 - 调用方期望的返回值,内存是在调用方的栈帧里提前预留的,和函数参数的内存区域完全独立。编译器没法把这两个地址合并,总不能要求调用方在调用函数前,就把参数的内存分配到返回值的位置吧?这完全不符合函数调用的参数传递规则。
举个实际调用的例子:当你写std::string res = foo(my_str);时,my_str会先被拷贝到foo的参数s(位于foo的栈上),而res的内存是在当前调用代码的栈上。编译器不可能让s直接用res的内存,因为s的创建是函数调用的前置步骤,早于res的构造逻辑,两者的内存位置从一开始就不重叠。
反过来,如果是函数内部创建的局部变量返回,比如:
std::string foo(){ std::string s; return s; }
编译器就可以直接把s的内存分配到调用方预留的返回值位置,因为s是函数内部创建的,编译器完全能控制它的地址,这就是NRVO能生效的原因。
内容的提问来源于stack exchange,提问作者EL IAS
相关产品推荐
相关产品推荐

