C++ 如果返回参数,是否可以复制省略?

C++ 如果返回参数,是否可以复制省略?,c++,gcc,c++11,compiler-construction,clang,C++,Gcc,C++11,Compiler Construction,Clang,考虑一个函数,该函数按值获取对象,对其执行一些操作并返回该对象,例如: std::string MyToUpper (std::string s) { std::transform(s.begin(), s.end(), s.begin(), std::toupper); return s; } 现在,您可以使用临时命令调用此函数: std::string Myupperstring = MyToUpper("text"); 从概念上讲,不需要复制。在这种情况下,现代

考虑一个函数,该函数按值获取对象,对其执行一些操作并返回该对象,例如:

std::string MyToUpper (std::string s)
{
      std::transform(s.begin(), s.end(), s.begin(), std::toupper);
      return s;
}
现在,您可以使用临时命令调用此函数:

std::string Myupperstring = MyToUpper("text");
从概念上讲,不需要复制。在这种情况下,现代编译器是否能够删除所有副本?如果没有,是否只有行动?那么这个案例呢:

std::string Mylowerstring("text");
std::string Myupperstring = MyToUpper(std::move(Mylowerstring));

我不这么认为。有些副本可以,也可能会被复制 已消除,但NVRO无法应用,因为它依赖于 变量构造在与返回相同的位置 价值除了使用值参数外,参数是 由调用方构造,调用方无法(通常)看到 参数将被返回,因此无法在
正确的位置

最多可以省略两个概念副本中的一个。如果您向函数传递一个临时变量,那么根据C++11 12.8/31的第三个项目符号,可以省略该副本:

当临时类对象。。。将被复制/移动…,可以省略复制/移动操作

回报是不能忽略的;这只能针对临时变量(根据上面引用的规则)或局部变量,根据第一个项目符号:

在返回语句中。。。当表达式是 非易失性自动对象(,函数或catch子句参数除外))。。。复制/移动操作可以省略

在没有省略的情况下,返回值被视为右值,并在可能的情况下移动(在这里也是可能的);如果函数参数是右值,则会移动它们,就像在两个示例中一样

从概念上讲,不需要复制。在这种情况下,现代编译器是否能够删除所有副本

<强>是的,如果函数是内联的,则是可能的。< /强>但是,我想考虑下面的代码示例而不是您的代码示例,因为<代码> STD::String 是一个未被驯服的野兽,充满了模糊的优化。

让我们考虑一个例子,使用代码< int >代码> s。调用者有

{1,2,3}
,并希望在此基础上创建一个
std::vector
,其中包含
{2,4,6}
。(这大致类似于在调用者处使用文本
“text”
,并希望构建一个包含
“text”
std::string

代码:

#包括
#包括
使用名称空间std;
向量mult(向量v){
适用于(内部和外部:v)
e*=2;
返回v;
}
int main(){
向量v(mult({1,2,3}));
对于(int i:v)
printf(“%d\n”,i);
}
如果我使用GCC4.7.2将其编译为:
g++-O3-fwhole-program-Wall-Wextra-std=c++11-S file.cpp
,我在程序集中正好得到一个
std::vector
析构函数调用矢量是在适当的位置创建的。生成的程序集尽可能好

如果我编译了完全相同的代码,但省略了
-fwhole program
标志,则
mult()
函数不会内联,并且我得到了对
std::vector
的析构函数的两个调用。生成的程序集也比前一种情况差得多

Clang不知道
-fwhole程序
标志,因此我将
静态
关键字添加到
mult()

静态向量mult(向量v){…

然后它也会在适当的位置创建向量


对于值参数,参数由调用方构造,调用方 无法看到(通常)参数将被返回,因此 无法在正确的位置构造它


我在上面做了什么(内联
mult()
)使调用者能够看到参数将被返回,实际上,结果已被构造到位。

在这种情况下,编译器不允许在返回中删除副本,而且这里也没有隐式的
move
。@Simple:如果类型是可移动的,则返回值将被移动(如“string”在这里)。与您的问题无关,但您的代码具有未定义的行为(假设它已编译,但可能没有)。
std::transform
将使用
char
调用
std::toupper
,如果对纯
char
进行签名(通常是这种情况),则会导致未定义的行为.我检查了当标准参数和函数参数用作
返回
中的表达式时,它们被隐式移动(认为它只是自动变量),因此参数将被删除,参数将被移动,然后返回值将被删除。
#include <cstdio>
#include <vector>
using namespace std;

vector<int> mult(vector<int> v) {
  for (int& e : v)
    e *= 2;
  return v;
}

int main() {
  vector<int> v( mult({1, 2, 3}) );
  for (int i : v)
    printf("%d\n", i);
}