C++ 返回类型是实例化的还是简单赋值的
我一直在思考我的问题的答案,所以我不得不问,返回类型是实例化的还是简单地赋值的 以下面的示例为例:C++ 返回类型是实例化的还是简单赋值的,c++,return,return-value,C++,Return,Return Value,我一直在思考我的问题的答案,所以我不得不问,返回类型是实例化的还是简单地赋值的 以下面的示例为例: class Convert { public: int getValue (std::string const& _text); }; Convert convert; int total(0); total = convert.getValue("488"); 因此;从getValue()成员函数返回结果时发生了什么,步骤是什么?是否创建了返回类型int的实例,并将
class Convert {
public:
int getValue (std::string const& _text);
};
Convert convert;
int total(0);
total = convert.getValue("488");
因此;从getValue()
成员函数返回结果时发生了什么,步骤是什么?是否创建了返回类型int
的实例,并将值从临时int
复制到total
变量中,或者返回值直接分配到total
中,而无需创建临时返回类型int
因为我的一些代码有
void getValue(int&\u result,std::string const&\u text)
;但是,int-getValue(std::string-const&_-text)
更符合逻辑。您的完整表达式total=convert.getValue(“488”)代码>是一个赋值表达式。计算它会将右侧的值分配给变量总计
。右边的值是计算子表达式convert.getValue(“488”)的结果代码>。此值是类型为int
的临时值(右值)
我真的不认为有更好的方式来表示“评估右侧的结果的值被分配给左侧”
优化编译器可能会很好地意识到类是空的,并且使用0
初始化total
是不可观察的,并且会将所有内容都折叠成非常短的内容。复制省略是一种允许的优化,几乎每个编译器都支持
复制省略意味着在某些情况下,创建临时副本,然后将该临时副本复制到命名变量中,然后销毁该临时副本,可以直接构造该变量
结合返回值优化和移动语义,这意味着返回可移动的复杂对象是有效的。对于像int
这样的类型,“好像”规则也在运行中:编译器可以执行任何行为,就像执行了代码行或代码块一样,并且编译器知道当您复制/移动int
时会发生什么(即,基本上没有),因此他们可以跳过这些复制/移动
为了确保RVO和复制省略正确发生,您需要执行以下操作:
int function() {
int retval = 8; // create the return value in one spot, this makes NRVO possible
// code goes here
return retval; // you can have more than one return statement in most compilers
}
int result = function(); // initialize the variable result by assigning the return value of the function to it.
如果您执行上述操作,大多数编译器将直接在结果
变量存储中构造返回
对象,如果在结果
中可以看到函数
的主体,则根本不会出现副本(有些编译器甚至可以在看不到函数
的主体时执行此操作)
在C++11中还有其他技巧
int function() {
return {7}; // guaranteed to directly construct the return value without a copy
}
int result = function(); // even if copy elision is not done, the temporary `int` is moved into `result`.
如果您阻止复制省略:
int function() {
int foo = 7;
int bar = 3;
// code
if (foo>bar)
return foo;
else
return bar;
}
只要返回局部变量,就会发生隐式移动。您还可以显式地将std::move
移到返回值中
现在,对于像int
这样简单和小的类型,所有这些优化都是毫无意义的。当您处理更大、更昂贵的对象时,例如std::vector
的std::vector
,每个对象中都有10 MB的数据,这些技术意味着按值返回的效率与传递要仔细填充的指针的效率一样。任何一种选择都可以基于优化……正如您所说,按值返回更符合逻辑,您应该坚持这一点……这是更好的方法谢谢您,雅克。我说你对编译器很了解!读了你的解释后,我的理解在很多方面都发生了翻天覆地的变化。我不认为函数中具有相同类型的变量可以得到优化,从而将计算直接放入结果
变量,而不需要临时变量。^^我只有一个后续问题,正如您所说的“确保RVO和复制省略正确发生”,您有int result=function()代码>在对“function()”进行二次调用时,它是否会制动,例如result=function()代码>,没有初始化?@8位蝶形结构,第二个示例将复制或移动构造。对于像int这样的普通类型,编译器将对作为构造的副本执行相同的操作,并且它可以跳过任何早期的构造,因为它知道您从未读过它。