2

我一直在考虑我的问题的答案,所以我不得不问,返回类型是实例化的还是简单地赋值?

以下面的示例为例:

class Convert {

public:

    int getValue (std::string const& _text);

};


Convert convert;
int total(0);

total = convert.getValue("488");

因此;从getValue()成员函数返回结果时发生了什么,步骤是什么?是创建了返回类型的实例,int然后将值从临时复制inttotal变量中,还是将返回值直接分配给了,total而无需创建临时返回类型int

因为我的一些代码有void getValue (int& _result, std::string const& _text);然而,int getValue (std::string const& _text)更合乎逻辑。

4

2 回答 2

2

复制省略是几乎每个编译器都支持的允许优化。

复制省略意味着在某些情况下,创建临时副本,然后将该临时副本复制到命名变量中,然后销毁临时副本,可以直接构造变量。

与返回值优化和移动语义一起,意味着返回可移动的复杂对象是高效的。对于像intas-if 规则这样的类型也在运行中:编译器可以做任何表现得好像代码行或代码块被执行的事情,并且编译器理解当你复制/移动时会发生什么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.

如果您执行上述操作,大多数编译器将retval直接在result变量存储中构造对象,根本不会出现任何副本 iffunction的主体可以看到result(有些可能会这样做,即使您看不到functionmayhap 的主体)

在 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,所有这些优化都毫无意义。当您处理更大、昂贵的对象时,例如 a std::vectorof std::vectors,其中每个对象都包含 10 MB 的数据,这些技术意味着按值返回最终与传递要仔细填充的指针一样有效。

于 2013-06-19T20:55:21.373 回答
0

您的完整表达式total = convert.getValue("488");是一个赋值表达式。评估它会将右边的值赋给变量total。右边的值是评估子表达式的结果convert.getValue("488");。该值是类型的临时值(右值)int

我真的不认为有更好的说法是“评估右侧结果的值分配给左侧”。

一个优化的编译器很可能意识到这个类是空的,并且totalwith的初始化0是不可观察的,并且把所有的东西都折叠成非常短的东西。

于 2013-06-19T20:32:46.503 回答