C++ ABI如何处理RVO和NRVO?

NoS*_*tAl 5 c++ abi rvo nrvo

我很困惑与问候如何编译和链接处理的事实,在电话会议上要求ER功能的依靠,如果函数使用静脉阻塞或NRVO不同.

这可能是我的误解,但我的假设是通常没有RVO或NRVO

std::string s = get_string();
Run Code Online (Sandbox Code Playgroud)

如果get_string不执行N?RVO但是如果get_string执行N?RVO调用代码什么也不做,并且s由函数get_string构造到位,则涉及从get_string的结果移动构造s .

编辑:这是我如何设想get_string调用程序操作,如果没有N?RVO:

  1. 调用get_string()
  2. get_string结果现在在堆栈上,调用者使用它来构造s

现在还有RVO

  1. 调用get_string()
  2. 当get_string完成时,堆栈上没有结果,get_string构造为s,调用者不需要做任何事情来构造s.

Mil*_*nek 9

无论如何,调用者都为返回对象分配空间.从调用者的角度来看,函数是否使用RVO并不重要.

你也混淆了两个独立的复制品.有一个RVO,它将函数局部变量的副本省略到返回值,并且从函数返回值到被初始化的对象的另一个副本也经常被省略.

基本上,没有任何省略,你可以把OP的调用看作是这样的(忽略任何别名问题,这实际上都可以直接在汇编中实现):

void get_string(void* retval)
{
    std::string ret;
    // do stuff to ret
    new(retval) std::string(std::move(ret));
}

char retval[sizeof(std::string)];
get_string(retval);
std::string s(std::move(*(string*)retval));
Run Code Online (Sandbox Code Playgroud)

字符串ret被复制(或移动,在这种情况下)两次:一次从ret所述retval缓冲器,并从一次retvals.

现在,应用NRVO后,只会get_string改变定义:

void get_string(void* retval)
{
    std::string& ret = *new(retval) std::string;
    // do stuff to ret
}
Run Code Online (Sandbox Code Playgroud)

从来电者的角度来看,一切都没有改变.该函数只是直接初始化它将返回到调用者为返回值分配的空间的对象.现在字符串只移动一次:从.retvals.

现在调用者也可以删除副本,因为不需要分配单独的返回值,然后将其复制到正在初始化的对象中:

char retval[sizeof(std::string)];
get_string(retval);
std::string& s(*(string*)retval);
Run Code Online (Sandbox Code Playgroud)

以这种方式,s直接初始化get_string,并且不执行复制或移动.