14

Is there any reason not to send a parameter as a const & , instead of by value, when it will not be changed and no copy will be made? My understanding is that a const by value parameter is the same as without the const (and won't overload each other) so it will still be copied.

I know it's best for large objects to send by const &, but I don't know where the line for this is. Or if even small parameters should be sent by value if they won't be changed or copied.

Note:: I tried searching for this but the topic is fairly vague so I did not find any good answers, I apologize if this has been answered already (found many questions about when to use const when to use const & but not about the advantages of value vs const & for objects not obviously large).

Stu
  • 380
  • 4
  • 12
  • 2
    you might find this article interesting: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – lccarrasco Jul 22 '11 at 15:19
  • Exactly the type of thing I was looking for thanks! The keywords are so general it was hard for me to search. – Stu Jul 22 '11 at 15:33
  • @lccarrasco: Dave Abrahams is talking about returning objects by value from within functions. The question is about input parameters to functions. In this case the OP should pass objects other than native types by const reference. – Praetorian Jul 22 '11 at 15:34
  • Conceptually, a reference is an alias. It is _not a pointer_, although in some cases the compiler has no other choice but to secretly implement it as a pointer. Insofar it is true that sometimes passing primitive types by value may be as fast or faster. In many cases though, I've seen the compiler do truly amazing stuff with references, entirely eleminating them, basically as if you used the original variable in the other function's scope. – Damon Jul 22 '11 at 15:38
  • @iccarrasco's link is about the return value, indeed, but that's also an important thing to consider. Especially if you're wondering about the details of how arguments (and return values!) are passed during a function call, it's well worth knowing about RVO ... don't forget to compile with optimizations, too! – Kerrek SB Jul 22 '11 at 15:39
  • @Praetorian: Ah yes. The article is still interesting though. – Stu Jul 22 '11 at 15:39

3 Answers3

24

There's generally nothing wrong with passing read-only arguments as const-references, and for any sort of heavy-weight class that's surely the most efficient way to do it.

You might want to consider passing primitive types by copy, though, because there making the reference might actually incur more cost than just copying (e.g. copying would just fit into one register, while a reference might be implemented with a pointer, etc.).

Also, you can probably pass std::shared_ptr and iterators by value, they're made for that.

As for passing by const-value, that's an implementation detail. Use it like this:

// Declaration:
int foo(int n, double d); // No "const"! Constness is not part of the interface.

// Definition
int foo(int n, const double d) // implementation detail
{
  while (n--) { if (d > n) return n; }
}

In the implementation, you may or may not choose to use the argument variables directly and modify them (like n), or you may choose to treat them as read-only (like d), and you declare the arguments appropriately.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 3
    I did not think of the pointer copying being just as expensive or worse for primitive types, thanks. – Stu Jul 22 '11 at 15:30
  • 8
    Worthwhile to point out, if you pass a reference-counting handle (like `shared_ptr`) by reference across a thread boundary then it becomes **impossible to ever safely decrement the reference count** -- you *have* to pass by value in this case. – spraff Jul 22 '11 at 15:33
14

As a rule of thumb, you should pass primitive types such as pointers, int, bool, float, double by (non-const) value, and object types such as std::string, std::vector and custom classes by (const) reference. As an exception to this rule, there are light-weight classes that are specifically designed to be passed by value, such as smart pointers.

Passing a value by const value, e.g. void foo(const double bar), makes no sense -- why shouldn't foo be allowed to modify its copy of bar? Declaring the parameter as const has no use here.

Passing primitives by reference makes little sense as well. Behind the scenes, when a parameter is passed by reference, a pointer is passed by value. Copying a pointer is usually just as expensive as copying a primitive type (such as int), and parameters of type const int& look pretty weird to most C++ programmers.

Ferdinand Beyer
  • 64,979
  • 15
  • 154
  • 145
  • 4
    There are some people (I am not among them) who actually prefer `const double bar`. They say it prevents bugs causes by overwriting the value of a parameter in a function. – Fred Foo Jul 22 '11 at 15:32
  • Just to add to @larsmans' comment, using `const double bar` prevents you from accidentally doing `if (bar = 5)` instead of `==`. But that's at the cost of limiting what you can do with `bar`. Your algorithm might demand in-place modification of `bar` for some reason. I guess it's just a tradeoff of flexibility vs. safety. Depends how much you want to trust the next programmer! – Cam Jackson Jan 29 '13 at 04:18
3

Unless an interface demands it, primitives should be passed by value. Otherwise, const& is a better practice.

boost::is_fundamental

Identifying primitive types in templates

Community
  • 1
  • 1
Tom Kerr
  • 10,444
  • 2
  • 30
  • 46