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).
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.
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.
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
Related
Since a reference (some-type&) behaves as a constant pointer (some-type * const), passing an argument via a "constant reference to pointer" parameter (some-type * const&) seems a bit redundant, because
if the parameter is some-type *
I'm copying it,
I can't edit the original because I just don't handle it;
if the parameter is some-type * const&
I'm not copying it,
I can't edit the orignal because I hold it as a const entity.
So in some way the only difference between the two is that the former incurs a copy, whereas the latter doesn't.
In turn, this means that this difference can be relatively important for std::shared_ptrs, which can be bigger than raw pointers and std::unique_ptrs.
But is that (passing std::shared_ptrs by const& if they are "heavy") the only usecase for passing pointer arguments by const&?
As regards the observation that the pointer aspect of the question is unnecessary, I think that when talking of non pointer-like data types, it's kind of easy to see the biggest advantage (or one of the biggest advantages) of passing them by value vs by const&: in both cases you protect the actual entity at the call site, but in the latter you avoid copying a potentially huge object.
For pointer-like entities such as raw pointers and smart pointers, I look at them as things which are meant to be at least similar in size to each other, with the std::shared_ptr allowed to diverge from the similarity.
Anyway, if we are dealing with obviously small raw pointers and std::unique_ptrs and small std::shared_ptrs, so that we can consider the aforementioned advantage of passing by const& negligible, is there any other reason why I might want to pass them by const&?
Without a reference you cannot overload a function based on constness of the parameter:
void foo(int* const) { /* do something */ }
void foo(int*) { /* do something else */ } // error : redefinition of foo
But you can do so with a const/non-const reference:
void bar(int*&) { std::cout << "non-const\n";}
void bar(int* const&) { std::cout << "cosnt\n";}
int main() {
int* y = nullptr;
int* const x = nullptr;
bar(y);
bar(x);
}
To answer the title of your question, for raw pointers, no. Passing a pointer by reference is usually more expensive, and if it's a const reference you can't use it to modify the caller's pointer anyway so there's no benefit (and I really don't know what #463035818_is_not_a_number is getting at, who would want ever such overloads?)
For a smart pointer, it's different. std::unique_ptr cannot be passed by value at all (since the copy constructor is deleted) so you can either pass by reference (if you just want to get at what it's pointing to) or you can move from it (to transfer ownership). And in fact, there's not really much point in passing it by const reference since you can pass my_unique_ptr.get() as a raw pointer - by value - and not lose anything.
std::shared_ptr can be passed by value, but doing that will bump the reference count (and then decrement it again when the copy goes out of scope), and there is a cost associated with that so you might want to pass it by const reference since that may well be cheaper. But, again, if the function you're calling is non-owning, why not just pass a raw pointer? This is the cheapest option of all.
The only reason to copy a shared_ptr is to make sure that the pointer it is managing does not disappear out from beneath you, and that implies you're hanging on to it for some reason (so-called 'shared ownership'). So yes, if that's the semantics you want, pass it by const reference and make a copy at the receiving end.
I am starting to come to grips with const in terms of a reference parameter. The way I see it is that a constant reference parameter basically sets the parameter in question to the original memory space that calls the function into question. And since it is const, the value in itself cannot change.
I have found a solution with regards to a code that delivers matrix multiplication A=BC:
vector<vector<double> > mult(const vector<vector<double> >& B, const vector<vector<double> >& C)
{ ...;
return A;
}
int main()
{
vector<vector<double> > B, C;
cout << mult(B,C) << endl;
return 0;
}
I agree with the structure of the code but I am confused about the neccessity of "const" and "&". Surely the code would be exactly the same if I excluded both from the above? For "&" one could perhaps that we use less memory space by not creating an extra space for the parameters of "mult". But the use of const seems unnecessary to me.
The '&' prevents the copy constructor from being called, i.e., prevents a duplicate copy being made. It is more efficient this way because you avoid the constructor on the invocation and the destructor on the exit.
The 'const' keyword communicates to the caller that the object to which the reference refers will not be changed in the function. It also allows the function to be called with constant vectors as input. In other words, if B and C are constant, you couldn't call mult() without the const keyword in the signature.
It's been a while in C++ for me, but I think that's the gist. I'm certainly open to corrections on my answer.
There are only a few times when a const reference is, strictly-speaking, necessary. The most common is when you need to pass a const object by reference. The type system will prevent this unless the function promises not to modify the object. It can also make a difference when a function is overloaded to do something different when the object is const, and you specifically want the const version. (The latter is probably bad design!)
It would alternatively be possible to remove the const qualifier from the function argument, and to give any overloaded functions different names. In fact, references in C++ are syntactic sugar for C-style pointers, and it would be possible to replace void foo (T& x) with void foo(T* x) and every occurrence of x inside foo with (*x). Adding const T& or T* const simply means that the program will not be able to modify the object through that reference or pointer.
C had no const keyword until 1989, and you could do all the same things without it, but it’s present in order to help developers avoid bugs related to modifying the wrong variable.
It is not really necessary. As long as you pass in non-const parameters to your function, the program will not behave differently.
I can state a few examples in your case:
If one of the parameters you have to pass is const, it will not work.
Furthermore, you won't be able to do something like mult({{1, 2}, {3, 4}}, b); because that temporary object can only implicitly convert into a const reference.
If you put the definition and declaration in separate translation units (i.e. .cpp files) then the compiler might miss some optimization potential, because it wouldn't be able to assume that mult() doesn't modify its parameters.
Another argument is simply that const shows your intents more clearly.
See a few more reasons on isocpp.
The reference & prevents an unnecessary copy. Your parameter type is a std::vector, which means that copying will involve memory allocations, and for performance reasons you do not want that.
On a side note, if your code is meant to manipulate matrices, then a std::vector of std::vector is very inappropriate for performance reasons, as it makes it extremely cache inefficient and causes unnecessary dynamic allocations. You would rather use a 1D std::array and wrap it to handle 2D indices nicely. std::array has sizes known as compile time, which means that every function you pass a specific std::array to knows its size on compile-time which is good for performance, especially as std::array makes it possible to avoid dynamic allocation.
int sum(const int a,int b)
{
b=10;
// a=5; error
return (a+b);
}
in above example a is const and not b.
So a as read-only variable. If you try to change the value of a you get error. That means you have to use value of a which pass when function is call.
Quite new to C++. I have seen people usually pass objects by reference in operator overloading. Well, I can't figure out when it is really necessary. As in the code below, if I remove ampersand in declaration of object c1 and c2 in operator+, still I'll get the same result. Is there any reason to pass-by-reference in this case when we do not want to modify c1 or c2?
#include <iostream>
class Keys
{
private:
int m_nKeys;
public:
Keys(int nKeys) { m_nKeys = nKeys; }
friend Keys operator+(const Keys &c1, const Keys &c2);
int GetKeys() { return m_nKeys; }
};
Keys operator+(const Keys &c1, const Keys &c2)
{
return Keys(c1.m_nKeys + c2.m_nKeys);
}
int main()
{
Keys cKeys1(6);
Keys cKeys2(8);
Keys cKeysSum = cKeys1 + cKeys2;
std::cout << "There are " << cKeysSum.GetKeys() << " Keys." << std::endl;
system("PAUSE");
return 0;
}
Operators are just like ordinary functions, just with "fancy" names :)
(e.g. operator+() instead of sum())
So, the same parameter passing rules that you apply to functions, can be applied to overloaded operators as well.
In particular, when you have a parameter that is not cheap to copy (e.g. an int, a float, are examples of cheap to copy parameters; a std::vector, a std::string, are examples of not cheap to copy parameters), and you observe this parameter inside your method (i.e. it's an input read-only parameter), then you can pass it by const reference (const &).
In this way, basically it's just like the address of the original argument is passed to the function, so there is no deep-copy involved. Deep-copies can be very expensive, e.g. think of a vector with a big number of elements.
So, to recap, you pass by const reference when:
the parameter just is not cheap to copy (e.g. for ints, float, etc. just
don't bother: passing by value is just fine)
the parameter is observed in the function/operator implementation
(i.e. it's an input read-only parameter)
If you pass by reference then there is no copy of the object made, which for more complicated classes could greatly improve performance.
In this case the performance cost may be marginal, and it's conceivable the compiler could optimise it all out, but it's still worth doing. Later the Keys class may change into something more complex.
Advantages of passing by reference:
It allows us to have the function change the value of the argument, which is sometimes useful.
Because a copy of the argument is not made, it is fast, even when used with large structs or classes.
We can pass by const reference to avoid unintentional changes.
We can return multiple values from a function.
Disadvantages of passing by reference:
Because a non-const reference can not be made to a literal or an expression, reference arguments must be normal variables.
It can be hard to tell whether a parameter passed by reference is meant to be input, output, or both.
It’s impossible to tell from the function call that the argument may change. An argument passed by value and passed by reference looks the same. We can only tell whether an argument is passed by value or reference by looking at the function declaration. This can lead to situations where the programmer does not realize a function will change the value of the argument.
Because references are typically implemented by C++ using pointers, and dereferencing a pointer is slower than accessing it directly, accessing values passed by reference is slower than accessing values passed by value.
You can read the below:
http://www.cs.fsu.edu/~myers/c++/notes/references.html
Consider a vector of long having 10 million entries in it. If you prototype a function like:
void foo(vector<long> vl)
{
}
It will cause assignment-operator (or copy-constructor) of vector<long> - and that would need to copy all those 10m elements. Later destructor for this temporary object (vl) would de-allocate memory and perform other cleanup. It will definitely impact performance
There are classes, specially around synchronization providers (critical sections etc.), and some smart pointer classes that prevent copy-constructor and/or assignment-operators - so that assignment or object creation doesn't happen by mistake. Though move-constructor or move-assignment-operator may be implemented.
There are many questions about "when do I use reference and when pointers?". They confused me a little bit. I thought a reference wouldn't take any memory because it's just the address.
Now I made a simple Date class and showed them the community of code-review. They told me not to use the reference in the following example. But why?
Someone told me that it'll allocate the same memory a pointer would allocate. That's the opposite of what I learned.
class A{
int a;
public:
void setA(const int& b) { a = b; } /* Bad! - But why?*/
};
class B{
int b;
public:
void setB(int c) { b = c; } /* They told me to do this */
};
So when do I use references or pointers in arguments and when just a simple copy? Without the reference in my example, is the constant unnecessary?
It is not guaranteed to be bad. But it is unnecessary in this specific case.
In many (or most) contexts, references are implemented as pointers in disguise. Your example happens to be one of those cases. Assuming that the function does not get inlined, parameter b will be implemented "under the hood" as a pointer. So, what you really pass into setA in the first version is a pointer to int, i.e. something that provides indirect access to your argument value. In the second version you pass an immediate int, i.e. something that provides direct access to your argument value.
Which is better and which is worse? Well, a pointer in many cases has greater size than an int, meaning that the first variant might passes larger amount of data. This might be considered "bad", but since both data types will typically fit into the hardware word size, it will probably make no appreciable difference, especially if parameters are passed in CPU registers.
Also, in order to read b inside the function you have to dereference that disguised pointer. This is also "bad" from the performance point of view.
These are the formal reasons one would prefer to pass by value any parameters of small size (smaller or equal to pointer size). For parameters or bigger size, passing by const reference becomes a better idea (assuming you don't explicitly require a copy).
However, in most cases a function that simple will probably be inlined, which will completely eliminate the difference between the two variants, regardless of which parameter type you use.
The matter of const being unnecessary in the second variant is a different story. In the first variant that const serves two important purposes:
1) It prevents you from modifying the parameter value, and thus protects the actual argument from modification. If the reference weren't const, you would be able to modify the reference parameter and thus modify the argument.
2) It allows you to use rvalues as arguments, e.g. call some_obj.setA(5). Without that const such calls would be impossible.
In the second version neither of this is an issue. There's no need to protect the actual argument from modification, since the parameter is a local copy of that argument. Regardless of what you do to the parameter, the actual argument will remain unchanged. And you can already use rvalues as arguments to SetA regardless of whether the parameter is declared const or not.
For this reason people don't normally use top-level const qualifiers on parameters passed by value. But if you do declare it const, it will simply prevent you from modifying the local b inside the function. Some people actually like that, since it enforces the moderately popular "don't modify original parameter values" convention, for which reason you might sometimes see top-level const qualifiers being used in parameter declarations.
If you has light-weight type like a int or long you should use passing by value, because there won't be additional costs from work with references. But when you passing some heavy types, you should use references
I agree with the reviewer. And here's why:
A (const or non-const) reference to a small simple type, such as int will be more complex (in terms of number of instructions). This is because the calling code will have to pass the address of the argument into setA, and then inside setA the value has to be dereferenced from the address stored in b. In the case where b is a plain int, it just copies the value itself. So there is at least one step of a memory reference in saving. This may not make much of a difference in a long runtime of a large program, but if you keep adding one extra cycle everywhere you do this, then it does soon add up to noticeably slower.
I had a look at a piece of code that went something like this:
class X
{
vector v;
public:
...
void find(int& index, int b);
....
}
bool X::find(int &index, int b)
{
while(v[index] != b)
{
if (index == v.size()-1)
{
return false;
}
index++;
}
return true;
}
Rewriting this code to:
bool X::find(int &index, int b)
{
int i = index;
while(v[i] != b)
{
if (i == v.size()-1)
{
index = i;
return false;
}
i++;
}
index = i;
return true;
}
meant that this function went from about 30% of the total execution of some code that called find quite a bit, to about 5% of the execution time of the same test. Because the compiler put i in a register, and only updated the reference value when it finished searching.
References are implemented as pointers (that's not a requirement, but it's universally true, I believe).
So in your first one, since you're just passing an "int", passing the pointer to that int will take about the same amount of space to pass (same or more registers, or same or more stack space, depending on your architecture), so there's no savings there. Plus now you have to dereference that pointer, which is an extra operation (and will almost surely cause you to go to memory, which you might not have to do with the second one, again, depending on your architecture).
Now, if what you're passing is much larger than an int, then the first one could be better because you're only passing a pointer. [NB that there are cases where it still might make sense to pass by value even for a very large object. Those cases are usually when you plan to create your own copy anyway. In that case, it's better to let the compiler do the copy, because the overall approach may improve it's ability to optimize. Those cases are very complex, and my opinion is that if you're asking this question, you should study C++ more before you try to tackle them. Although they do make for interesting reading.]
Passing primitives as const-reference does not save you anything. A pointer and an int use the same amount of memory. If you pass a const-reference, the machine will have to allocate memory for a pointer and copy the pointer address, which has the same cost as allocating and copying an integer. If your Date class uses a single 64-bit integer (or double) to store the date, then you don't need to use const-reference. However, if your Data class becomes more complex and stores additional fields, then passing the Date object by const-reference should have a lower cost than passing it by value.
When writing a C++ function which has args that are being passed to it, from my understanding const should always be used if you can guarantuee that the object will not be changed or a const pointer if the pointer won't be changed.
When else is this practice advised?
When would you use a const reference and what are the advantages over just passing it through a pointer for example?
What about this void MyObject::Somefunc(const std::string& mystring) What would be the point in having a const string if a string is in fact already an immutable object?
Asking whether to add const is the wrong question, unfortunately.
Compare non-const ref to passing a non-const pointer
void modifies(T ¶m);
void modifies(T *param);
This case is mostly about style: do you want the call to look like call(obj) or call(&obj)? However, there are two points where the difference matters. If you want to be able to pass null, you must use a pointer. And if you're overloading operators, you cannot use a pointer instead.
Compare const ref to by value
void doesnt_modify(T const ¶m);
void doesnt_modify(T param);
This is the interesting case. The rule of thumb is "cheap to copy" types are passed by value — these are generally small types (but not always) — while others are passed by const ref. However, if you need to make a copy within your function regardless, you should pass by value. (Yes, this exposes a bit of implementation detail. C'est le C++.)
Compare const pointer to non-modifying plus overload
void optional(T const *param=0);
// vs
void optional();
void optional(T const ¶m); // or optional(T param)
This is related to the non-modifying case above, except passing the parameter is optional. There's the least difference here between all three situations, so choose whichever makes your life easiest. Of course, the default value for the non-const pointer is up to you.
Const by value is an implementation detail
void f(T);
void f(T const);
These declarations are actually the exact same function! When passing by value, const is purely an implementation detail. Try it out:
void f(int);
void f(int const) {/*implements above function, not an overload*/}
typedef void C(int const);
typedef void NC(int);
NC *nc = &f; // nc is a function pointer
C *c = nc; // C and NC are identical types
The general rule is, use const whenever possible, and only omit it if necessary. const may enable the compiler to optimize and helps your peers understand how your code is intended to be used (and the compiler will catch possible misuse).
As for your example, strings are not immutable in C++. If you hand a non-const reference to a string to a function, the function may modify it. C++ does not have the concept of immutability built into the language, you can only emulate it using encapsulation and const (which will never be bullet-proof though).
After thinking #Eamons comment and reading some stuff, I agree that optimization is not the main reason for using const. The main reason is to have correct code.
The questions are based on some incorrect assumptions, so not really meaningful.
std::string does not model immutable string values. It models mutable values.
There is no such thing as a "const reference". There are references to const objects. The distinction is subtle but important.
Top-level const for a function argument is only meaningful for a function implementation, not for a pure declaration (where it's disregarded by the compiler). It doesn't tell the caller anything. It's only a restriction on the implementation. E.g. int const is pretty much meaningless as argument type in a pure declaration of a function. However, the const in std::string const& is not top level.
Passing by reference to const avoids inefficient copying of data. In general, for an argument passing data into a function, you pass small items (such as an int) by value, and potentially larger items by reference to const. In the machine code the reference to const may be optimized away or it may be implemented as a pointer. E.g., in 32-bit Windows an int is 4 bytes and a pointer is 4 bytes. So argument type int const& would not reduce data copying but could, with a simple-minded compiler, introduce an extra indirection, which means a slight inefficiency -- hence the small/large distinction.
Cheers & hth.,
The main advantage of const reference over const pointer is following: its clear that the parameter is required and cannot be NULL.
Vice versa, if i see a const pointer, i immedeately assume the reason for it not being a reference is that the parameter could be NULL.