Could someone explain this code? I don't understand line 3:
MyString MyString::operator+(const MyString &str)
{
MyString ss(*this); //----> explain this part
ss += str;
return ss;
}
Thanks!
This code:
MyString ss(*this);
Says "declare a new variable of type MyString that's named ss, and initialize it as a copy of *this." Inside of a member function, this is a pointer to the receiver object (the object that the member function is acting on), so *this is a reference to the receiver object. Consequently, you can read this as "make a new MyString that's called ss and is a copy of the receiver object."
The idiom being used here is implementing operator + in terms of operator +=. The idea is to make a copy of the receiver object, use operator += to add the parameter to the copy, and then to return the copy. It's a widely-used trick that simplifies the implementation of freestanding operators given implementation of the corresponding compound assignment operator.
Hope this helps!
This is an instance of the common code reuse technique to implement one operator in terms of another.
Suppose we have already defined a compound-plus operator:
class X
{
X & operator+=(const X&);
};
This unary operator allows us to write a += b, it modifies a and returns a reference to itself. This is all fine and good. Now if we also want to provide a copying, binary plus opearator a + b, which returns a the new value by value and leaves both a and b unchanged, then we want to take advantage of the code we've already written for the compound operator. We do so by calling the unary operator on a temporary copy of a:
X X::operator+(const X & b) const { return X(*this) += b; }
^^^^^^^^
temporary copy
This is exactly what your code does, only a bit more verbosely. You could as well have written return MyString(*this) += str;
There are other idioms with follow a similar spirit, such as implementing non-const access in terms of const access, copy-assign in terms of copy-construct and swap, and move-assign in terms of move-construct and swap. It always boils down to avoiding code duplication.
It's a constructor for MyString that takes the value of the current object (of type MyString) as its argument.
From what I can tell that is a copy constructor which creates a new MyString with the contents of the current MyString object.
ss is a new string which gets constructed with a copy constructor from the original string.
Related
I have a theoretical question:
Usually, in an operator= implementation, it returns *this. But what happens if we instead returned *other, where other is the right hand side of the assignment?
Thanks
Reason for returning *this is to enable assignment in this form
a = b = c
this is same as
a.operator=( b.operator=(c))
If you return other, compiler wont be able to compile this kind of assignments.
The purpose of returning *this from the assignment operator is to allow for assignment chaining, e.g.
int x = 2;
int y = x = 5; // Equivalent to: 'int y = (x = 5);'
The copy assignment operator is usually declared as:
T& operator=(const T& other);
Here the argument other is declared as const and can thus not be returned. Returning by const T& will also act differently as the caller can not assign to the returned reference, thus disallowing assignment chaining.
Often you will also assign with a temporary. If you customize the behaviour of the assignment operator to return a reference to this temporary it can result in dangling references and other dangerous behaviours.
std::string s;
(s = "abc") = "def"; // Can't assign to rhs.
It is possible to customize the behaviour of the assignment operator to achieve different behaviours, but you should generally refrain from doing so to keep the meaning of the operator clear. If you want custom behaviour it's better to provide a function with a good descriptive name.
More info about operator overloading can be found here.
Well their will be two factual differences :
You will be forced to return a reference to a const instance from your operator= or a copy
You assignment will return a reference on its right hand side instead of its left hand side
Mostly what this means is you will surprise some developers that might exploit the return value of your assignment thinking it gives back the left hand side as most objects do.
But there is not so many people who sanely intend to write things like:
(a = b).do_action();
And since you just assigned the right value to the left one and you are returning either a const instance or a copy, most of the operations will most likely result in the same thing no matter if they are called on the left or right instance. So basically most of the time it won't change anything to your life.
However except if you are a boost::spirit developer, you are highly encouraged to avoid such things for the sanity of your colleagues :)
1) What is the difference between:
complex& operator = (const complex& c);
and
complex operator = (complex c);
2) are they the same if I define (in the second case) a copy constructor?
complex::complex (const complex& c){
//code
}
3) what is the funcion of const?
Those are very different
Do you want chained assignments? Return *this.
a = b = c; // Chained assignment
Default assignment in C++ supports chaining, so it's a good idea to keep this rule.
To support this type of assignment each operation has to return a reference to *this or return a copy:
complex& operator = (const complex& c)
{
// do assignment
return *this;
}
or
complex operator = (const complex& c)
{
// do assignment
return *this;
}
But this simple job should be light and efficient. Assume no RVO or moving is available, then returning a reference rather than a copy is preferred.
Another reason that I prefer returning a reference is to get rid of a confusing thing in my mind. See these two scenarios:
// Returning a reference
a = 1;
b = 2;
c = 3;
(a = b) = c;
After assignments, a=3 b=2 c=3. Because, first b assigns to a and returns a reference to a, then c assigns to that reference and a changes again.
// Returning a copy
a = 1;
b = 2;
c = 3;
(a = b) = c;
After assignments, a=2 b=2 c=3. Because, first b assigns to a and returns a temporary copy, then c assigns to that temporary object (no effect on a or b).
As you can see, the results are different. Ignoring what happens and which one is better. You should choose a way which is popular and expected for programmers. I believe C++ programmers by watching (a = b) = c expect first result.
Therefore you should use first one.
About keyword const:
When you pass an object by reference to a function, the function can modify it. You can put a const to protect it against unwanted changes.
1) the first one is the idiomatic C++ version. it says that it takes a reference to the argument (not make a copy) and will return a reference to a complex (not a copy) which is usually the object being assigned to (i.e. *this).
the second one can work but it makes unnecessary copies & u can't call functions on the object that gets assigned to, like this: (a = b).dosth() because it returns a different object. i mean it will compile but it will call dosth on a temp object.
2) they aren't the same ever, however the second one wont work if u dont have accessible copy ctor (or sometimes move ctor).
3) const is a promise that you won't modify the argument. so in a = b you don't want to modify b and const enforces that. u don't need it in the second version (pass by value) because you can't modify it anyway, because its just a copy.
They aren't the same, the first one passes references so the objects remain in place in memory and the second will need the copy-ctor as complex objects will be copied in and out of the function. The first is canonical and what you want, the second isn't used because it's unnecessarily wasteful.
the const is a way of saying "I promise I won't change c! So don't worry about it!". This allows the user to provide the actual class (in your case complex) by reference without worrying it will change unexpectedly.
"reference" - chosen by adding the & sign - means that this function actually uses the same object that the user gave, from the same memory. Since it is using the same object, it is important that you promised not to change that object.
Without the & - your second example - you don't pass the same object, you pass a copy of that object. So the const is unnecessary (although still legal) because the user doesn't care if you change a copy.
The difference? Time (and memory for large classes). If you pass the reference to the object - you don't need to copy that object. That saves you time (the time it takes to copy the object) and memory (the memory the object needs).
The second form takes and returns value by copy rather than by reference, which is often inefficient.
complex operator=(complex c);
The parameter c is passed in as a copy of the original. For simple datatypes like int this doesn't matter, but if complex is, well, complex, this can result in unnecessary allocations/deallocations and hinder performance.
Passing by reference, as in:
complex& operator=(complex& c);
Means that the object passed to the operator isn't copied.
The second difference is what they return. The correct form of the operator is to return a reference to itself. The first form you provide actually returns a copy of the object, which again can be inefficient.
Finally, again the correct form of the operator takes the input object as a const reference. This is more a stylistic issue than anything to do with performance - but one would not reasonably expect the assignment operator to modify the input object, and specifying it as const prevents this.
So to sum up,
complex& operator=(const complex& c);
is the correct form.
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.
As I've understand, when overloading operator=, the return value should should be a non-const reference.
A& A::operator=( const A& )
{
// check for self-assignment, do assignment
return *this;
}
It is non-const to allow non-const member functions to be called in cases like:
( a = b ).f();
But why should it return a reference? In what instance will it give a problem if the return value is not declared a reference, let's say return by value?
It's assumed that copy constructor is implemented correctly.
Not returning a reference is a waste of resources and a yields a weird design. Why do you want to do a copy for all users of your operator even if almost all of them will discard that value?
a = b; // huh, why does this create an unnecessary copy?
In addition, it would be surprising to users of your class, since the built-in assignment operator doesn't copy likewise
int &a = (some_int = 0); // works
A good general advice when overloading operators is 'do as primitive types do', and the default behavior of assignment to a primitive type is that.
Not returning anything could be an option, to disable assignment inside other expressions if you feel the need, but returning a copy does not make sense at all: if the caller wants to make a copy they can make it out of the reference, if they do not need the copy there is no need to generate a temporary that is not needed.
Cause f() can modify a. (we return a non-const reference)
If we return a value (a copy) of a, f() will modify the copy, not a
I'm not sure how often you'd want to do it, but something like: (a=b)=c; requires a reference to work.
Edit: Okay, there is a bit more to it than that. Much of the reasoning is semi-historical. There's more reason you don't want to return an rvalue than just avoiding an unnecessary copy into a temporary object. Using a (minor) variation on an example originally posted by Andrew Koenig, consider something like this:
struct Foo {
Foo const &assign(Foo const &other) {
return (*this = other);
}
};
Now, assume you're using an old version of C++ where assignment returned an rvalue. In that case, (*this=other); will yield that temporary. You're then binding a reference to the temporary, destroying the temporary, and finally returning a dangling reference to the destroyed temporary.
Rules that have been enacted since (extending the life of a temporary used to initialize a reference) would at least mitigate (and might completely cure) this problem, but I doubt anybody re-visited this particular situation after those rules had been written. It was a bit like an ugly device driver that includes kludges to work around dozens of bugs in different versions and variations of the hardware -- it could probably be refactored and simplified, but nobody's quite sure when some seemingly innocuous change will break something that currently works, and ultimately nobody wants to even look at it if they can help it.
If your assignment operator does not take a const reference parameter:
A& A::operator=(A&); // unusual, but std::auto_ptr does this for example.
or if the class A has mutable members (reference count?), then it is possible that the assignment operator changes the object being assigned from as well as assigned to. Then if you had code like this:
a = b = c;
The b = c assignment would occur first, and return a copy (call it b') by value instead of returning a reference to b. When the a = b' assignment is done, the mutating assignment operator would change the b' copy instead of the real b.
Another potential problem -- returning by value instead of by reference could cause slicing if you have virtual assignment operators. I'm not saying that's a good idea, but it could be a problem.
If you intend to do something like (a = b).f() then you will want it to return by reference so that if f() mutates the object, it is not mutating a temporary.
In real code (i.e. not things like (a=b)=c), returning a value is unlikely to cause any compile errors, but it is inefficient to return a copy because creating a copy can often be expensive.
You can obviously come up with situation where a reference is needed, but those rarely -- if ever -- come up in practice.
This is Item 10 of Scott Meyers' excellent book, Effective C++. Returning a reference from operator= is only a convention, but it's a good one.
This is only a convention; code that doesn't follow it will compile. However, the convention is followed by all the built-in types as well as by all the types in the standard library. Unless you have a good reason for doing things differently, don't.
If you're worried that returning the wrong thing might silently cause unintended side effects, you could write your operator=() to return void. I've seen a fair bit of code that does this (I assume out of laziness or just not knowing what the return type should be rather than for 'safety'), and it causes few problems. The kind of expressions that need to use the reference normally returned by operator=() are pretty rarely used, and almost always easy code an alternative for.
I'm not sure I'd endorse returning void (in a code review I'd probably call it out as something you shouldn't do), but I'm throwing it out there as an option to consider if you want to not have to worry about how oddball uses of the assignment operator might be handled.
late edit:
Also, I should have originally mentioned that you can split the difference by having your operator=() return a const& - that will still permit assignment chaining:
a = b = c;
But will disallow some of the more unusual uses:
(a = b) = c;
Note that this makes the assignment operator have semantics similar to what it has in C, where the value returned by the = operator is not an lvalue. In C++, the standard changed it so the = operator returns the type of the left operand, so it is an lvalue, but as Steve Jessop noted in a comment to another answer, while that makes it so the compiler will accept
(a = b) = c;
even for built-ins, the result is undefined behavior for built-ins since a is modified twice with no intervening sequence point. That problem is avoided for non-builtins with an operator=() because the operator=() function call is a sequence point.
Returning by reference reduces the time of performing chained operations. E. g. :
a = b = c = d;
Let's see the actions which would be called, if operator= returns by value.
Copy assignment opertor= for c makes c equal to d and then creates temporary anonymous object (calls copy ctor). Let's call it tc.
Then operator= for b is called. Right hand side object is tc. Move assignment operator is called. b becomes equal to tc. And then function copies b to temporary anonymous, let's call it tb.
The same thing happens again, a.operator= returns temporary copy of a. After operator ; all three temporary objects are destroyed
Altogether: 3 copy ctors, 2 move operators, 1 copy operator
Let's see what will change if operator= will return value by reference:
Copy assignment operator is called. c becomes equal to d, reference to lvalue object is returned
The same. b becomes equal to c, reference to lvalue object is returned
The same. a becomes equal to b, reference to lvalue object is returned
Altogether: only three copy operators is called and no ctors at all!
Moreover I recommend you to return value by const reference, it won't allow you to write tricky and unobvious code. With cleaner code finding bugs will be much easier :) ( a = b ).f(); is better to split to two lines a=b; a.f();.
P.S.:
Copy assignment operator : operator=(const Class& rhs).
Move assignment operator : operator=(Class&& rhs).
If it returned a copy, it would require you to implement the copy constructor for almost all non-trivial objects.
Also it would cause problems if you declare the copy constructor private but leave the assignment operator public... you would get a compile error if you tried to use the assignment operator outside of the class or its instances.
Not to mention the more serious problems already mentioned. You don't want it to be a copy of the object, you really do want it to refer to the same object. Changes to one should be visible to both, and that doesn't work if you return a copy.