c++ copy construct parameter passed by value

你说的曾经没有我的故事 提交于 2019-12-10 18:48:52

问题


I want freeFunct to do non const stuff on its own copy of object a.

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.

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

回答1:


First, as already said, don't do freeFunct3 if the semantics of the free function is to only modify its "own" object.

Second, there are differences between freeFunct1 and freeFunct2, relating to move optimization [C++11], exception safety, and potentially code size.

With freeFunct2 (taking by reference-to-const):

  1. It will always construct a new copy of the argument, never move it [C++11].
  2. If the copy construction of A throws an exception, it will throw inside the body of the function.
  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).

With freeFunct1 (taking by value):

  1. [C++11] You can avoid a copy if A has a move constructor and you pass an rvalue (e.g. call freeFunct1(A(args))).
  2. If the copy (or move) construction of A throws an exception, it will throw at the call site.
  3. If A's copy (or move) constructor is inlined, it will be expanded multiple times, at each call site.

Alternatively, you can overload on lvalue/rvalue reference to avoid unnecessarily copying rvalues:

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



回答2:


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.




回答3:


IMO, the first is the best and the last is the worst.

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.




回答4:


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. 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.



来源:https://stackoverflow.com/questions/18631374/c-copy-construct-parameter-passed-by-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!