I wonder in c++ about the operator overloading forms of the below like:
ClassName & operator+(ClassName &other)
ClassName operator+(ClassName &other)
Classname operator+(const ClassName &other)
Classname operator+(const Classname other)
Classname operator+(Classname other)
What are the difference of usage ??
Just for reference: none of the quoted operators is the one normally
actually overloaded! The one which is normally overloaded is more like
this (assuming it is in the same namespace as ClassName):
ClassName operator+ (ClassName const& op1, ClassName const& op2) {
ClassName rc(op1);
rc += op2;
return rc;
}
There are some variations how this operator can be implemented. In
particular the first argument may be passed by value to avoid the copy
in the implementation: in some cases the copy could be elided. This particular implementation using a named variable and returning it by name is intended to enable copy elision (as #juanchopanza pointed out, return ClassName(op1) += op2; isn't allowed to elide the copy for the return value).
With respect to your actual question, it is important to distinguish
between references and values:
When a value like ClassName is used, the object being passed to a
function or returned from a function is a copy. When the class
in question is trivial, that is just OK but if the class is more
complicated and allocates memory for its members there may be some
cost in creating actual copies. On the other hand, semantically it is
often necessary to use a copy. For example, the result of an addition
is normally a different object and, thus, needs to be a copy.
To take the edge out of the some of the costs, the compiler tries
hard to avoid copies when it can. For example, when returning a
local variable the copy is in many cases elided or the object is,
at least, moved (assuming C++11 or later is used and the class has
a move constructor).
When a reference like ClassName& or ClassName const& is used,
the entity is actually just a name for an object. No copy is made
but an object needs to exist somewhere. The presence of const vs.
the absence of const just indicates whether all methods or only
const methods can be called or whether a reference can be passed
where another reference is needed: a non-const reference can
be converted to a const reference but not vice verse.
For the purpose of parameters, the key difference between const
reference and non-const reference is that temporary objects
cannot bind to non-const reference while they can bind to
const references.
With that sorted, here is a run-through of the different declarations of
the operator+():
ClassName & operator+(ClassName &other)
This declaration takes a non-const reference as argument and returns
a non-const reference. For the argument this means that it can't
be a temporary but rather needs to have a name. For the return that
means that the returned object needs to be kept alive. Normally the
addition creates a new object and trying to keep an object alive
is bound to not work. If ClassName is really expensive to copy
you might not want to provide an operator+() but rather just
an operatr+=() which semantically produces the same result as
operator+() but does so in-place.
ClassName operator+(ClassName &other)
This declaration has the primary constraint that the argument is
a non-const reference, i.e., the argument cannot be a temporary
object but has to be an lvalue, i.e., something which is somehow
named. However, the arguemnt won't be copied.
ClassName operator+(const ClassName &other)
This declaration works with temporaries and is one of the two likely
candidates of how a member operator+() would look like. The argument
still isn't copied but because it is [logically] immutable temporary
objects can be used as arguments.
ClassName operator+(const ClassName other)
This will copy the argument. For the purpose of the declaration
the const will be meaningless and it can actually differ between
different declarations of the same function. When the definition
uses this declaration it means that the argument is copied, i.e., the
operator+() has a local version but it can't actually change this
copy. Most likely it will need to create another copy to produce a
result. Correspondingly, I think defining a function with a const
value argument is utterly pointless: if you want a constant, use
const ClassName& or ClassName const& (these are identical; I do
prefer the latter notation as it results in consistent placement).
ClassName operator+(ClassName other)
Like the previous declaration this one copies the argument but the
argument is mutable. Assuming the oepration is commutative, you can
readily mutate other to produce the return value. Note, however,
that copying other won't be elided (the compiler is not allowed
to elide copying function parameters) but it can be moved. Assuming
ClassName is either cheap to copy or other is used as the basis
for the result, this is the other likely candidate how the operator
is defined.
First one returns a reference, and takes a reference - this means that you can theoretically change both arguments, and you return a reference, which can be changed too. This is usually not what you want to do( 2 + 3 doesn't return 5 that can be reassigned to 17).
Second one is the same, but no reference returned.
Third has const reference - a reference which can't be modified. This is usually what you want to do, since you get element fast(you get the element), but you can't change it(incidentally or not).
Fourth one is like a third, but you copy an argument, and make it const for some reason. This makes little sense.
And the last one just takes a copy.
There isn't much difference between some of them - some of them make little sense if you think about what operator+ has to do; the area where they differ is mostly how you get the argument - and most of the time, you want to get it fast, so const ClassName& other is probably your best bet.
Related
The lhs and rhs are passed by constant reference (const Type&).
CVector operator+ (const CVector& lhs, const CVector& rhs) {
CVector temp;
temp.x = lhs.x + rhs.x;
temp.y = lhs.y + rhs.y;
return temp;
}
When it is lightweight(cheap) data to copy (e.g. for ints, float ,char etc. passing by value is just fine)
The parameter is observed in the function/operator implementation (i.e. it's an input read-only parameter)
as a sum up of both points you will get we will get why we should pass by constant reference.
For clear understanding see http://www.cs.fsu.edu/~myers/c++/notes/references.html
Prefer to follow these guidelines for choosing how to take parameters. For input-only parameters:
Always const-qualify all pointers or references to input-only parameters.
Prefer taking inputs of primitive types (e.g., char, float) and value objects that are cheap to copy (e.g., Point, complex) by value.
Prefer taking inputs of other user-defined types by reference to const.
Consider pass-by-value instead of reference if the function requires a copy of its argument. This is conceptually identical to taking a reference to const plus doing a copy, and it can help compiler to better optimize away temporaries.
For output or input/output parameters:
Prefer passing by (smart) pointer if the argument is optional (so callers can pass null as a "not available" or "don't care" value) or if the function stores a copy of the pointer or otherwise manipulates ownership of the argument.
Prefer passing by reference if the argument is required and the function won't store a pointer to it or otherwise affect its ownership. This states that the argument is required and makes the caller responsible for providing a valid object.
Reference: [C++ Coding Standards: 101 Rules, Guidelines, and Best Practices] #25. Take parameters appropriately by value, (smart) pointer, or reference
In few words, to ensure immutability of data.
Excerpts from the link below:
When an argument is passed by reference, a reference is created to the actual argument (which takes minimal time) and no copying of values takes place. This allows us to pass large structs and classes with a minimum performance penalty.
References allow the function to change the value of the argument, which in many cases is undesirable. If we know that a function should not change the value of an argument, but don’t want to pass by value, the best solution is to pass by const reference.
A const reference is a reference that does not allow the variable being referenced to be changed. Consequently, if we use a const reference as a parameter, we guarantee to the caller that the function will not (and can not) change the argument!
Ref: http://www.learncpp.com/cpp-tutorial/73-passing-arguments-by-reference/
why arguments are passed as constant
=> when one wants to prevent respective data members from being altered in the called function.
why constant references
=> to Prevent the creation of temporary objects
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.
//old school '98 c++, no C++0x stuff
std::string getPath();
void doSomething()
{
const std::string &path = getPath(); //const reference to an rvalue
... // doSomething with path
}
void doSomething2()
{
const std::string path = getPath(); //regular variable
... // doSomething with path
}
what are the differences between doSomething and doSomething2 and which one is prefferable?
Is it safe to use const reference to returned rvalue in doSomething?
Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?
Is it safe to use const reference to returned rvalue in doSomething?
Yes, this is perfectly fine. The language has an specific clause that guarantees that if you bind a reference to an rvalue a temporary is created and the lifetime is extended until the end of the scope where the reference is created.
Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?
In both cases the cost is the same, as the compiler will do RVO (return value optimization)
what are the differences between doSomething and doSomething2 and which one is prefferable?
The main difference is that in one case you are giving a name to the real object and in the other case the name is given to a reference. The compiler should generate exactly the same code in both versions.
That being said, I find the use of the const& to be misleading. It gives the impression that the local function has a reference to some object somewhere, but it really has a copy (with no name). To realize that this is a copy the maintainer will have to look and verify the signature of the function that is being called. In the case of the value the behavior is more obvious: the function maintains a copy of whatever is returned by the function (which might be a value or reference).
The second difference is that you are only legally allowed to bind a const reference, which means that the function cannot modify the object. In the case of storing a value, the type can be non-const and the function could modify that object, so the approach is more flexible.
In C++03 the only reason to use the const& trick is in the case where you know that the function returns a value, you know that the type derives from a well known base, and you don't want to name the type [Take a look at ScopeGuard]. In C++11 that use is no longer important, as you can just use auto to let the compiler figure out the type automatically.
(from other comments it seems this might be C++ standards version dependant as to guarentees when you bind a reference to an rvalue about its lifespan - this answer reflects C++ classic)
doSomething has a reference to what?
doSomething2 has a copy of something that may not exists anymore which is fine
lets look at getPath():
in general it will take the return value, copy it to the stack and then copy that to the lhs
it can just assign directly to the lhs
it can return "hello" which will create a string on the stack - this cannot be referenced because it is temporary (the problem with doSomething)
it can return a static const string - in which case it can be completely inlined and assigned to the lhs
The reference version could have a dangling reference if the std::string was allocated inside the function getPath() and destroyed when returning from that function.
Then, it's dangerous usage.
If you had a class holding that string and the class outlives the scope of that const std::string & reference, something as MyClass::getPath(), then, in that case, the reference wouldn't be dangling.
The second version will always work.
In C++, the concept of returning reference from the copy assignment operator is unclear to me. Why can't the copy assignment operator return a copy of the new object? In addition, if I have class A, and the following:
A a1(param);
A a2 = a1;
A a3;
a3 = a2; //<--- this is the problematic line
The operator= is defined as follows:
A A::operator=(const A& a)
{
if (this == &a)
{
return *this;
}
param = a.param;
return *this;
}
Strictly speaking, the result of a copy assignment operator doesn't need to return a reference, though to mimic the default behavior the C++ compiler uses, it should return a non-const reference to the object that is assigned to (an implicitly generated copy assignment operator will return a non-const reference - C++03: 12.8/10). I've seen a fair bit of code that returns void from copy assignment overloads, and I can't recall when that caused a serious problem. Returning void will prevent users from 'assignment chaining' (a = b = c;), and will prevent using the result of an assignment in a test expression, for example. While that kind of code is by no means unheard of, I also don't think it's particularly common - especially for non-primitive types (unless the interface for a class intends for these kinds of tests, such as for iostreams).
I'm not recommending that you do this, just pointing out that it's permitted and that it doesn't seem to cause a whole lot of problems.
These other SO questions are related (probably not quite dupes) that have information/opinions that might be of interest to you.
Has anyone found the need to declare the return parameter of a copy assignment operator const?
Overloading assignment operator in C++
A bit of clarification as to why it's preferable to return by reference for operator= versus return by value --- as the chain a = b = c will work fine if a value is returned.
If you return a reference, minimal work is done. The values from one object are copied to another object.
However, if you return by value for operator=, you will call a constructor AND destructor EACH time that the assignment operator is called!!
So, given:
A& operator=(const A& rhs) { /* ... */ };
Then,
a = b = c; // calls assignment operator above twice. Nice and simple.
But,
A operator=(const A& rhs) { /* ... */ };
a = b = c; // calls assignment operator twice, calls copy constructor twice, calls destructor type to delete the temporary values! Very wasteful and nothing gained!
In sum, there is nothing gained by returning by value, but a lot to lose.
(Note: This isn't meant to address the advantages of having the assignment operator return an lvalue. Read the other posts for why that might be preferable)
When you overload operator=, you can write it to return whatever type you want. If you want to badly enough, you can overload X::operator= to return (for example) an instance of some completely different class Y or Z. This is generally highly inadvisable though.
In particular, you usually want to support chaining of operator= just like C does. For example:
int x, y, z;
x = y = z = 0;
That being the case, you usually want to return an lvalue or rvalue of the type being assigned to. That only leaves the question of whether to return a reference to X, a const reference to X, or an X (by value).
Returning a const reference to X is generally a poor idea. In particular, a const reference is allowed to bind to a temporary object. The lifetime of the temporary is extended to the lifetime of the reference to which it's bound--but not recursively to the lifetime of whatever that might be assigned to. This makes it easy to return a dangling reference--the const reference binds to a temporary object. That object's lifetime is extended to the lifetime of the reference (which ends at the end of the function). By the time the function returns, the lifetime of the reference and temporary have ended, so what's assigned is a dangling reference.
Of course, returning a non-const reference doesn't provide complete protection against this, but at least makes you work a little harder at it. You can still (for example) define some local, and return a reference to it (but most compilers can and will warn about this too).
Returning a value instead of a reference has both theoretical and practical problems. On the theoretical side, you have a basic disconnect between = normally means and what it means in this case. In particular, where assignment normally means "take this existing source and assign its value to this existing destination", it starts to mean something more like "take this existing source, create a copy of it, and assign that value to this existing destination."
From a practical viewpoint, especially before rvalue references were invented, that could have a significant impact on performance--creating an entire new object in the course of copying A to B was unexpected and often quite slow. If, for example, I had a small vector, and assigned it to a larger vector, I'd expect that to take, at most, time to copy elements of the small vector plus a (little) fixed overhead to adjust the size of the destination vector. If that instead involved two copies, one from source to temp, another from temp to destination, and (worse) a dynamic allocation for the temporary vector, my expectation about the complexity of the operation would be entirely destroyed. For a small vector, the time for the dynamic allocation could easily be many times higher than the time to copy the elements.
The only other option (added in C++11) would be to return an rvalue reference. This could easily lead to unexpected results--a chained assignment like a=b=c; could destroy the contents of b and/or c, which would be quite unexpected.
That leaves returning a normal reference (not a reference to const, nor an rvalue reference) as the only option that (reasonably) dependably produces what most people normally want.
It's partly because returning a reference to self is faster than returning by value, but in addition, it's to allow the original semantics that exist in primitive types.
operator= can be defined to return whatever you want. You need to be more specific as to what the problem actually is; I suspect that you have the copy constructor use operator= internally and that causes a stack overflow, as the copy constructor calls operator= which must use the copy constructor to return A by value ad infinitum.
There is no core language requirement on the result type of a user-defined operator=, but the standard library does have such a requirement:
C++98 §23.1/3:
” The type of objects stored in these components must meet the requirements of CopyConstructible
types (20.1.3), and the additional requirements of Assignable types.
C++98 §23.1/4:
” In Table 64, T is the type used to instantiate the container, t is a value of T, and u is a value of (possibly const) T.
Returning a copy by value would still support assignment chaining like a = b = c = 42;, because the assignment operator is right-associative, i.e. this is parsed as a = (b = (c = 42));. But returning a copy would prohibit meaningless constructions like (a = b) = 666;. For a small class returning a copy could conceivably be most efficient, while for a larger class returning by reference will generally be most efficient (and a copy, prohibitively inefficient).
Until I learned about the standard library requirement I used to let operator= return void, for efficiency and to avoid the absurdity of supporting side-effect based bad code.
With C++11 there is additionally the requirement of T& result type for default-ing the assignment operator, because
C++11 §8.4.2/1:
” A function that is explicitly defaulted shall […] have the same declared function type (except for possibly differing ref-qualifiers and except that in
the case of a copy constructor or copy assignment operator, the parameter type may be “reference to non-const T”, where T is the name of the member function’s class) as if it had been implicitly declared
I guess, because user defined object should behave like builtin types.
For example:
char c;
while ((c = getchar()) != -1 ) {/* do the stuff */}
Copy assignment should not be void, otherwise assignment chain will not work
a = b = c;
// because assignment operator is right-associative
// it is equal to
a = (b = c); // oops, (b = c) return nothing, the code won't compile
Copy assignment should not return a value, otherwise unnecessary copy constructor and destructor will be called
// suppose a, b and c are of type X, which holds some resource that will take efforts to copy
a = b = c;
// is equal to
X temp1.X::( (b = c) ); // copy constructor called once
X temp2.X::( a.X::operator=(temp1) ); // copy constructor called twice; temp1 destructed inside a.X::operator=(temp1)
Copy assignment should not return rvalue reference cos it may have the assigned object moved. Again take the assignment chain for example
a = b = c;
// if a has a copy assignment overload that takes rvalue reference as argument like the following
X& operator=(X &&);
// then the result of (b = c) will be moved into a, and make b an invalid object afterwards
When overloading assignment operator of a class in C++, must its parameter be reference?
For example,
class MyClass {
public:
...
MyClass & operator=(const MyClass &rhs);
...
}
Can it be
class MyClass {
public:
...
MyClass & operator=(const MyClass rhs);
...
}
?
Thanks!
The parameter of an overloaded assignment operator can be any type and it can be passed by reference or by value (well, if the type is not copy constructible, then it can't be passed by value, obviously).
So, for example, you could have an assignment operator that takes an int as a parameter:
MyClass& operator=(int);
The copy assignment operator is a special case of an assignment operator. It is any assignment operator that takes the same type as the class, either by value or by reference (the reference may be const- or volatile-qualified).
If you do not explicitly implement some form of the copy assignment operator, then one is implicitly declared and implemented by the compiler.
Generally, it's up to you to decide, there is no must. The first variant is common and "canonic" and is ok for any assignment operator implementation.
When the question is speed, I think you should read this article about passing-by-value technique. This means that in some cases passing by value would be more effective than passing by const reference.
Also to mention, your second variant doesn't need const keyword, because passing by value acts as if a copy was created, so the original object definitely won't be changed.
C++ Operator Overloading Guidelines suggest, that the assignment operator gets a const reference. According to the site, the reason is that we do not want to change the argument (since const), but just the left hand side of the operator. Thus it saves time to pass it by reference.
It also points to the reason, why also a reference is returned by the assignment operator - operator chaining. In order to get a = (b = 1) working, it's necessary that (b = 1) returns a reference that can be assigned (=) to a.
Do you know the copy and swap idiom for exception safe assignment?
MyClass& operator=(const MyClass& rhs)
{
MyClass copy(rhs);
swap(copy);
return *this;
}
The implementation can be simplified (and in some cases sped up) via call by value:
MyClass& operator=(MyClass copy)
{
swap(copy);
return *this;
}
Ok I had this problem and I couldn't find a good answer so I'm going to share what I learned.
You could pass by value there is nothing wrong with that. (as you showed in your question.)
But the reason we pass the parameter by const reference is so the function doesn't make an actual copy of the value being called in. Its referenced, so its just pointing at that value wherever it is in the memory.
This saves processing time especially if its something big that has thousands of names...
In this case the time saved would be almost nothing.
And for the const, that ensures the user of the function that the referenced value is not going to be changed because it could be changed since you have access to the original location in the memory because its passed by reference..
If your function definition actually changes the value of the parameter being called in by const reference , it will be a compiler error, it wont let you do that. because when you put const, you are telling the compiler this value cannot be changed.