按值传递的 C++ 复制构造参数
c++ copy construct parameter passed by value
我希望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();
}
第一个是最好的:它允许调用方选择是复制还是移动他的对象,因此如果调用方不需要保留副本,可以更有效率。
freeFunct1(a); // "a" is copied and not changed
freeFunct1(std::move(a)); // "a" is moved and perhaps changed
第二个类似,但强制复制。
第三个,正如你所说,更容易出错,因为调用者必须知道它会修改参数。
首先,如前所述,如果自由函数的语义是只修改其"自己的"对象,则不要freeFunct3
。
其次,freeFunct1
和 freeFunct2
之间存在差异,涉及移动优化 [C++11]、异常安全和潜在的代码大小。
使用freeFunct2
(通过参考常量):
- 它将始终构造参数的新副本,永远不会移动它 [C++11]。
- 如果
A
的副本构造引发异常,它将抛出函数主体内部。 - 如果
A
的复制构造函数是内联的(而函数不是),它将在函数主体内部扩展一次(即使从多个不同位置调用函数)。
使用freeFunct1
(按值计算):
- [C++11] 如果
A
具有移动构造函数并且传递了右值(例如调用freeFunct1(A(args))
),则可以避免复制。 - 如果
A
的复制(或移动)构造引发异常,它将在调用站点抛出。 - 如果
A
的复制(或移动)构造函数是内联的,它将在每个调用站点多次扩展。
或者,您可以重载左值/右值引用以避免不必要地复制右值:
void freeFunct4(const A& a){
A b = a;
b.doStuff();
}
void freeFunct4(A&& a){
a.doStuff();
}
IMO,第一个是最好的,最后一个是最差的。
然而,相当多的人已经习惯了通过 const 引用传递,以至于他们默认会写 #2,即使在这种情况下他们需要它试图避免的副本。
第一个仅更改本地副本。第二个与第一个相同,但有额外的代码。第三个将更改a
对freeFunct3
的调用方可见,因为它是非常量引用。如果按照函数上方的注释调用,那么它实际上与第二个版本没有什么不同。
因此,如果您只想修改本地副本,而不将这些更改传递给调用方,那么我推荐第一个版本。
相关文章:
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么默认复制函数在按值发送参数时不调用?
- std::p ackaged_task 应该删除带有 const 参数的复制 c'tor
- 将参数传递给泛型 lambda 时复制构造函数不正确
- 如何确定捕获不可复制参数的 lambda 的类型?
- 复制 avcodec 参数
- 从函数参数 [C++] 复制整数数组
- 候选构造函数(隐式复制构造函数)不可行:第一个参数需要 l 值
- 使用另一个类中的参数复制构造函数
- 在 c++ 中从参数复制本地数组比从数组更快?
- 是否可以避免将参数复制到 lambda 函数?
- 可以使用默认参数复制包含 lambda 的 std::函数吗?
- C 指针节点帮助 - 将参数复制到链接的列表节点更改该节点的不同部分
- gcc 的 std::bind 在源中的哪个位置将参数复制到数据结构中?
- std::绑定参数复制行为
- 使用参数复制构造函数作为对派生类的引用
- 将指针类参数复制到类成员的好处
- 使用 2 参数复制构造函数
- 函数参数:复制或指针