C++ C++;ABI处理RVO和NRVO?
我对编译器和链接器如何处理函数调用er的要求因函数使用RVO或NRVO而不同这一事实感到困惑 这可能是我的误解,但我的假设是,通常没有RVO或NRVOC++ C++;ABI处理RVO和NRVO?,c++,abi,rvo,nrvo,C++,Abi,Rvo,Nrvo,我对编译器和链接器如何处理函数调用er的要求因函数使用RVO或NRVO而不同这一事实感到困惑 这可能是我的误解,但我的假设是,通常没有RVO或NRVO std::string s = get_string(); 如果get_字符串不为N?RVO,则涉及从get_字符串的结果中移动s的构造,但如果get_字符串不为N?RVO,则调用代码不执行任何操作,s由函数get_字符串就地构造 编辑: 下面是我如何想象在没有N?RVO的情况下让字符串调用者运行: 调用get_string() get_字符串
std::string s = get_string();
如果get_字符串不为N?RVO,则涉及从get_字符串的结果中移动s的构造,但如果get_字符串不为N?RVO,则调用代码不执行任何操作,s
由函数get_字符串就地构造
编辑:
下面是我如何想象在没有N?RVO的情况下让字符串调用者运行:
无论发生什么情况,调用者都会为返回对象分配空间。从调用方的角度来看,函数是否使用RVO并不重要 您还混淆了两个单独的副本省略。有一个RVO,它省略了从函数局部变量到返回值的副本,还有一个从函数返回值到被初始化对象的副本,也经常被省略 基本上,在没有任何省略的情况下,您可以将OP的调用看作是这样的(忽略任何别名问题,这实际上都是直接在汇编中实现的): 字符串
ret
被复制(本例中为移动)两次:一次从ret
复制到retval
缓冲区,一次从retval
复制到s
现在,应用NRVO后,只有get\u string
的定义会更改:
void get_string(void* retval)
{
std::string& ret = *new(retval) std::string;
// do stuff to ret
}
从来电者的角度来看,一切都没有改变。函数只是直接初始化要返回的对象,使其进入调用者为返回值分配的空间。现在字符串只移动一次:从retval
到s
现在,调用方还可以删除副本,因为不需要分配单独的返回值,然后将其复制到正在初始化的对象中:
char retval[sizeof(std::string)];
get_string(retval);
std::string& s(*(string*)retval);
通过这种方式,
s
由get\u string
直接初始化,并且不执行任何复制或移动。可能的复制不完全是,我知道RVO在概念上的作用。我想知道它是如何在ABI中实现的,因为调用者需要知道被调用者是如何实现的(或者我错了吗?)。它是堆栈,所以链接器不在乎。编译器只是在堆栈上一个接一个地排列变量。然后,所有变量访问都是当前堆栈顶部的反向引用。在调用之前创建的变量将稍微向下一点。@Galik-编辑的问题
char retval[sizeof(std::string)];
get_string(retval);
std::string& s(*(string*)retval);