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);
}