3

我希望 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

4 回答 4

6

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

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

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

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

于 2013-09-05T08:34:28.897 回答
3

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

freeFunct1其次,和之间存在差异freeFunct2,涉及移动优化[C++11]、异常安全和潜在的代码大小

使用freeFunct2(通过引用到常量):

  1. 它将始终构造参数的新副本,从不移动它 [C++11]。
  2. 如果复制构造A抛出异常,它将在函数体内抛出。
  3. 如果A的复制构造函数是内联的(而函数不是),它将在函数体内扩展一次(即使该函数是从多个不同的地方调用的)。

freeFunct1(按价值计算):

  1. A[C++11] 如果有移动构造函数并且传递右值(例如 call freeFunct1(A(args))) ,则可以避免复制。
  2. 如果复制(或移动)构造A抛出异常,它将在调用站点抛出异常。
  3. 如果A的复制(或移动)构造函数是内联的,它将在每个调用点展开多次。

或者,您可以重载左值/右值引用以避免不必要地复制右值:

void freeFunct4(const A& a){
    A b = a; 
    b.doStuff(); 
}
void freeFunct4(A&& a){
    a.doStuff(); 
}
于 2013-09-05T09:05:53.530 回答
2

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

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

于 2013-09-05T08:31:27.357 回答
1

第一个仅更改本地副本。第二个与第一个相同,但有额外的代码。a第三个将对调用者进行更改,freeFunct3因为它是非常量引用。如果在函数上方的注释中调用,那么它实际上与第二个版本没有什么不同。

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

于 2013-09-05T08:31:50.000 回答