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.
Related
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.
I came across the following code:
class MyClass {
// various stuff including ...
double *myarray;
double &operator() (const int n){
return myarray[n];
}
double operator() (const int n) const {
return myarray[n];
}
// various other stuff ...
}
So what is the practical difference in those two overloads of "()"? I mean, I know "The first one returns a reference to a double and the second one returns a double," but what does this mean practically? When would I use the one and when would I use the other? The second one (returning a double) seems pretty safe and straightforward. Is the first one ever dangerous in some way?
They differ in that first one allows you to modify your array element, while the second one only returns value, so you can:
with: double &operator()
MyClass mm;
mm(1) = 12;
but also:
std::cout << mm(1);
with: double operator()
// mm(1) = 12; // this does not compile
std::cout << mm(1); // this is ok
also, returning a reference is more common when using operator[], like when you use std::vector::operator[].
btw. its common to have two versions of operator() - one const and second non-const. Const version will be called on const objects, while the second one on non const. But usually their signature is :
double& operator() (const int n);
const double& operator() (const int n) const;
In general, the difference between pointers and references is that pointers can be changed and can also point to nullptr, i.e. to nothing. References are fixed.
In this example, though, operator() does not return a reference but a copy of the value, i.e. changing the value retrieved that way does not change the double in the class.
If it truly returned a double&, then you could use both of these methods interchangeably (of course with different notations in the usage), and offering both would merely be a welcome convenience for the user of this class.
what does this mean practically?
It means that the second method returns by-value, i.e. it makes a copy of the array-item/double and returns that copy to the caller. The first method returns by-reference, i.e. it doesn't make a copy of the double, but rather returns a reference to the original/in-the-array double's location, which the calling code can then use to directly access the in-the-array double, if it wants to. (if it helps, the indirection semantics of the returned reference are somewhat like pointer semantics, except with a syntax that is more similar to the traditional C/C++ by-value functionality)
When would I use the one and when would I use the other?
The by-value method is safer, since there is less chance of invoking undefined behavior; the by-reference method gives you some more flexibility (i.e. the caller could then update the item in the array by writing to the reference he received as a return value) and it might be more efficient in some situations (e.g. returning a reference avoids the need to copy the object, which could be an expensive operation if the object is large or complex). For a small object like a double, returning by-value is likely more efficient than returning by-reference.
Is the [by-reference method] ever dangerous in some way?
It can be -- for example, if you were to return a reference to an automatic/stack variable, that would cause undefined behavior, since the variable would be destroyed before the calling code could use it:
double & dont_ever_do_this()
{
double x = 5.0; // x will be destroyed as this method returns!
return x; // so returning a reference to x is a silly thing to do
}
Similarly, in your MyClass example, if the caller holds on to the returned reference and then tries to use it after myarray has been deleted, the caller will be reading from (or writing to) a memory location that is no longer valid, and that will cause undefined behavior (read: Bad Things) to happen.
And of course returning a non-const reference means the caller has the ability to change the contents of the returned array item without your class being aware of it, which might not be something you want to allow.
You can see value categories from this link.
http://en.cppreference.com/w/cpp/language/value_category
In double& operator() case you have lvalue expression and can use like lvalue (for assignment, print etc.)
MyClass class;
class(7) = 21;
or
std::cout << class(7);
And in double operator() const case you have rvalue expression.
In this case you also can use it with const object.
Why is it so important to be the reference and not just a copy of the object? For instance:
ostream& operator<<(ostream& out, const X & _class);
ostream& operator<<(ostream& out, const X _class);
What do we lose/win if we don't pass it as a reference?
In general, const& is preferred because, except for easy-to-copy types (Such as basic types) , copying is expensive (I recall, not always). But note that pass by value means the internal value of the function has nothing to do with the value passed to the function. That allows the compiler to do some assumptions and perform better optimizations in some cases. So in some cases, passing by value is better.
One of such cases is when you need a copy of the passed parameter:
void f( T param )
{
/* do something mutable with param */
}
In that cases, passing by value is prefereable over passing by const reference + hand copy, because the compiler could do assumptions based on value-semantics, and optimize the code. The rule is: Let the compiler decide how to pass by value.
In the case of streams, C++ streams are not copyable, thats why they are passed by reference. Is a non-const reference because IO operations change the internal state of the stream.
"reasonable pessimism" would summarise why we do this, and indeed why we prefer to pass a reference for any non-trivial object for which we don't need a copy.
We can be reasonably pessimistic that for anything other than a native type, making a copy is inefficient when compared to accessing the object via a reference.
We can also expect that not all objects are copyable, so writing a function that demands that our arguments are copyable is not only a possible inefficiency, it may well also lead to a program that cannot be compiled.
We can also expect that some objects' copy constructors will have side-effects (such as the deprecated auto_ptr). If we just want to query the state of an object, these side-effects would be undesirable. In the case of the auto_ptr, they would result in the deletion of the object controlled by the auto_ptr at the end of your function. Catastrophic.
The general rule would be:
If you are just going to read the object, pass a const reference
If you are going to modify the object, pass a reference (or pointer).
If you are definitely going to make a copy of the object, pass it by
value.
If you might make a copy, then either pass by const reference
(optimistic that we won't need to make a copy) or by value
(reasonably confident that the copy is required).
in the general case, passing a const& to a function is more efficient since it avoids making a copy.
Well the answer is obvious. Because if you do not, then the actual object will not be modified. Instead a copy will made and the copy will be modified, then later the copy will get destroyed.
If it is not const reference, then you need define a copy constructor to get it correct, and calling copy constructors would cost more memory and CPU obviously which is really unnecessary.
Let me put it straight. When you pass a reference of the object and modify the object contents in the definition of the overloaded operator, the same will get reflected on the object. For example: (Though a + operator is never overloaded this way for complex numbers, the example is just to prove a point). Say for an overloaded + operator
complex1& operator+(complex1 a)
{
a.real = a.real+1;
real=real+a.real;
img=img+a.img;
return *(this);
}
int main()
{
complex1 c1(1,2),c2(2.4,6.3);
complex1 c3 = c1+c2;
cout<<c2;
return 0;
}
Here, the changes made in real part of c2(i.e. addition of 1) will not be reflected when it is printed and will still be 2.4 if a reference is not passed. Thus passing a reference will increase the value of its real part by 1.
Secondly, passing a reference is more efficient as you pass only a reference to that object unlike passing by value where all the properties of the object gets copied.
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.
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