我希望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();
}
答案 0 :(得分:5)
第一个是最好的:它允许调用者选择是复制还是移动他的对象,因此如果调用者不需要保留副本,则可以更有效。
freeFunct1(a); // "a" is copied and not changed
freeFunct1(std::move(a)); // "a" is moved and perhaps changed
第二种类似,但强制复制。
正如你所说,第三个更容易出错,因为调用者必须知道它会修改参数。
答案 1 :(得分:3)
首先,如前所述,如果自由函数的语义只是修改其“自己的”对象,则不要freeFunct3
。
其次,freeFunct1
和freeFunct2
之间存在差异,与移动优化 [C ++ 11],异常安全有关,可能代码大小。
使用freeFunct2
(通过引用到const):
A
的副本构造引发异常,它会将抛出函数体。A
的复制构造函数(并且函数不是),它将在函数体内扩展一次(即使函数是从多个不同的地方)。使用freeFunct1
(按值计算):
A
有移动构造函数并且您传递了右值(例如,调用freeFunct1(A(args))
),则可以避免复制。A
的复制(或移动)构造引发异常,则会在呼叫站点上抛出。A
的复制(或移动)构造函数,则会在每个调用网站上多次展开 。或者,您可以在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引用。如果在函数上方的注释中调用,则它与第二个版本没有区别。
因此,如果您只想修改本地副本,而不将这些更改传递给调用者,那么第一个版本就是我推荐的。