简体   繁体   English

由value传递的c ++ copy构造参数

[英]c++ copy construct parameter passed by value

I want freeFunct to do non const stuff on its own copy of object a. 我希望freeFunct在它自己的对象副本a上做非const的东西。

Let's say that freeFunct is required to be a free function because in real code cases it takes many different parameters, calls several public functions from all of them and there is no point in making it a non-static member function of any class. 假设freeFunct需要是一个自由函数,因为在实际代码中它需要许多不同的参数,从所有这些函数调用几个公共函数,并且没有必要使它成为任何类的非静态成员函数。

Three different ways of declaring it come to my mind. 我想到了三种不同的宣告方式。

I have the feeling that the third solution is the worse. 我觉得第三种解决方案更糟糕。

Is there any difference between the first two? 前两个有什么区别吗?

Is there something better? 还有更好的东西吗?

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(); 
}

The first is best: it allows the caller to choose whether to copy or move his object, so can be more efficient if the caller doesn't need to keep a copy. 第一个是最好的:它允许调用者选择是复制还是移动他的对象,因此如果调用者不需要保留副本,则可以更有效。

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

The second is similar, but forces a copy. 第二个类似,但强制副本。

The third, as you say, is more error-prone, since the caller has to be aware that it will modify the argument. 正如你所说,第三个更容易出错,因为调用者必须知道它会修改参数。

First, as already said, don't do freeFunct3 if the semantics of the free function is to only modify its "own" object. 首先, freeFunct3如果自由函数的语义只是修改其“自己的”对象,则不要执行freeFunct3

Second, there are differences between freeFunct1 and freeFunct2 , relating to move optimization [C++11], exception safety , and potentially code size . 其次, freeFunct1freeFunct2之间存在差异,这与移动优化 [C ++ 11], 异常安全和可能的代码大小有关

With freeFunct2 (taking by reference-to-const): 使用freeFunct2 (通过引用到const):

  1. It will always construct a new copy of the argument, never move it [C++11]. 它总是构造一个新的参数副本,永远不会移动它[C ++ 11]。
  2. If the copy construction of A throws an exception, it will throw inside the body of the function . 如果A的复制结构抛出异常,它将抛出函数体内
  3. If A 's copy constructor is inlined (and the function is not), it will be expanded once , inside the body of the function (even if the function is called from multiple different places). 如果A的复制构造函数是内联的(函数不是),它将在函数体内展开一次 (即使从多个不同的地方调用函数)。

With freeFunct1 (taking by value): 使用freeFunct1 (按值计算):

  1. [C++11] You can avoid a copy if A has a move constructor and you pass an rvalue (eg call freeFunct1(A(args)) ). [C ++ 11]如果A有一个移动构造函数并且你传递一个rvalue(例如调用freeFunct1(A(args)) ),你可以避免复制。
  2. If the copy (or move) construction of A throws an exception, it will throw at the call site . 如果副本(或移动)建设A抛出异常,就会抛出在调用点
  3. If A 's copy (or move) constructor is inlined, it will be expanded multiple times , at each call site. 如果A的复制(或移动)构造函数被内联,它将在每个调用站点多次展开。

Alternatively, you can overload on lvalue/rvalue reference to avoid unnecessarily copying rvalues: 或者,您可以重载lvalue / rvalue引用以避免不必要地复制rvalues:

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

IMO, the first is the best and the last is the worst. IMO,第一个是最好的,最后一个是最差的。

Quite a few people, however, have gotten so accustomed to passing by const reference that they'll write #2 by default, even though in this case they need the copy that it's trying to avoid. 然而,相当多的人已经习惯于通过const引用传递他们将默认写入#2,即使在这种情况下他们需要它试图避免的副本。

The first changes only the local copy. 第一个只更改本地副本。 The second is the same as the first, but with extra code. 第二个与第一个相同,但有额外的代码。 The third will make changes to a visible to the caller of freeFunct3 as it's a non-const reference. 第三个将更改a到主叫方可见freeFunct3因为它是一个非const引用。 If called as in the comment above the function, then it's no different than the second version really. 如果在函数上面的注释中调用,那么它与第二个版本没有什么不同。

So if you just want to modify the local copy, without those changes being passed to the caller, then the first version is what I recommend. 因此,如果您只想修改本地副本,而不将这些更改传递给调用者,那么第一个版本就是我推荐的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM