c ++通过value传递的复制构造函数参数

时间:2013-09-05 08:28:33

标签: c++ pass-by-reference pass-by-value pass-by-const-reference

我希望freeFunct在自己的对象副本a上执行非常量的东西。

假设freeFunct必须是自由函数 因为在实际代码情况下它需要许多不同的参数, 从所有这些函数调用几个公共函数,但没有 指出使它成为任何类的非静态成员函数。

我想到了三种不同的宣告方式。

我觉得第三种解决方案更糟糕。

前两个之间有什么区别吗?

还有更好的东西吗?

void freeFunct1(A a){
    a.doStuff(); 
}

void freeFunct2(const A& a){
    A b = a; 
    b.doStuff(); 
}

/**users of freeFunct3 are expected 
 *to give a copy of their variable: 
 *{
 *    A b = a; 
 *    freeFunct3(b); 
 *}
 */
void freeFunct3(A& a){
    a.doStuff(); 
}

4 个答案:

答案 0 :(得分:5)

第一个是最好的:它允许调用者选择是复制还是移动他的对象,因此如果调用者不需要保留副本,则可以更有效。

freeFunct1(a);             // "a" is copied and not changed
freeFunct1(std::move(a));  // "a" is moved and perhaps changed

第二种类似,但强制复制。

正如你所说,第三个更容易出错,因为调用者必须知道它会修改参数。

答案 1 :(得分:3)

首先,如前所述,如果自由函数的语义只是修改其“自己的”对象,则不要freeFunct3

其次,freeFunct1freeFunct2之间存在差异,与移动优化 [C ++ 11],异常安全有关,可能代码大小

使用freeFunct2(通过引用到const):

  1. 它总是构造一个新的参数副本,永远不会移动它[C ++ 11]。
  2. 如果A的副本构造引发异常,它会将抛出函数体
  3. 如果内联A的复制构造函数(并且函数不是),它将在函数体内扩展一次(即使函数是从多个不同的地方)。
  4. 使用freeFunct1(按值计算):

    1. [C ++ 11]如果A有移动构造函数并且您传递了右值(例如,调用freeFunct1(A(args))),则可以避免复制。
    2. 如果A的复制(或移动)构造引发异常,则会在呼叫站点上抛出
    3. 如果内联A的复制(或移动)构造函数,则会在每个调用网站上多次展开
    4. 或者,您可以在lvalue / rvalue引用上重载以避免不必要地复制rvalues:

      void freeFunct4(const A& a){
          A b = a; 
          b.doStuff(); 
      }
      void freeFunct4(A&& a){
          a.doStuff(); 
      }
      

答案 2 :(得分:2)

IMO,第一个是最好的,最后一个是最差的。

然而,相当多的人已经习惯于通过const引用,他们默认会写#2,即使在这种情况下他们需要它试图避免的副本。

答案 3 :(得分:1)

第一个只更改本地副本。第二个与第一个相同,但有额外的代码。第三个将对a的调用者freeFunct3进行更改,因为它是非const引用。如果在函数上方的注释中调用,则它与第二个版本没有区别。

因此,如果您只想修改本地副本,而不将这些更改传递给调用者,那么第一个版本就是我推荐的。