Passing by value vs passing by reference

Hi everyone,

When I create class members or constructor such as this:

 
AreaExit(const Vector3& position, const Direction& direction, const std::string& target_area_name_);


I tend to do just that: I made the variables I pass const and by reference. Then in the constructor I copy them. (position_ = position; etc)

I do this because it seems to me this is most efficient: I pass by reference, so no unnecessary copy there. And since it's constant, I can't accidentally modify the values.

The question is: Is this the best way? Or should I just pass them by value and not worry about the (tiny) performance decrease?

Thanks!
Then in the constructor I copy them.

Best way is take by value and then to move in place. You will not lose anything noticeable if classes support move semantics (all standard classes do) and can even gain perfomance if user of your class will move their variables to your function.

Rule of thumb: if you are taking by const reference and all you do with the original is copy it, you should pass by value.
const reference is the better solution:
1
2
3
4
5
6
7
8
#include<iostream>

class A
{
public:
  A(const A &) { std::cout << "A" << std::endl; }
  A() { std::cout << "A" << std::endl; }
};

Reference:
1
2
3
4
5
6
7
8
9
10
11
12
void RefA(const A &a)
{
  A b = a;
}

int main()
{
  A x;
  RefA(x);

  return 0;
}
A
A
Copy:
1
2
3
4
5
6
7
8
9
10
11
12
void CopyA(A a)
{
  A b = a;
}

int main()
{
  A x;
  CopyA(x);

  return 0;
}
A
A
A


In case of refernce A exists 2 times
In case of copy A exists 3 times

Plus it minimizes the risk of shallow/pointer copy
Plus it minimizes the risk of shallow/pointer copy
You still have one copy at least. Other copies are not important, one is enough to trigger problems with improper copy constructor.
If you would define move constructor, it will make 1 copy and 1 move. It is still more than just single pointer pass and 1 copy in case of reference for abstract case, but, for most classes with expensive copy, move is extremely fast.
Also as I told before if you do not need your variable, you can move it to the constructor, transforming copy + move into 2 moves.

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
  public:
    A(std::string s) : name(std::move(s)) {}
  private:
    std::string name;
}

int main()
{
    std::string inp;
    std::cin >> inp;
    A a(std::move(inp)); //only 2 moves. 2 pointer assigment for GCC implementation of string
}
Versus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
  public:
    A(const std::string& s) : name(s) {}
  private:
    std::string name;
}

int main()
{
    std::string inp;
    std::cin >> inp;
    A a(inp); //pointer pass and 1 copy. more expensive than move implementation
}
Last edited on
If you would define move constructor
That's exactly the problem. For most complex objects (with inheritance etc.) it's hard to tell what the result of move is and hence to determine it's side effect.

const reference is straightforward and can be used in any situations (copy or not).

In most cases speed is not an issue while program flow is always an issue.

So I would normally prefer const reference as paramter.
Thanks a lot for the replies!
Topic archived. No new replies allowed.