operador de sobrecarga = retorno por valor o referencia?

1) What is the difference between:

complex& operator = (const complex& c);

y

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?

preguntado el 26 de septiembre de 13 a las 21:09

5 Respuestas

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 asigna a a y devuelve una referencia a a, entonces c assigns to that reference and a cambia de nuevo.

// Returning a copy
a = 1;
b = 2;
c = 3;
(a = b) = c;

After assignments, a=2 b=2 c=3. Because, first b asigna a 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.

Respondido el 26 de Septiembre de 13 a las 22:09

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 y 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.

Respondido el 26 de Septiembre de 13 a las 21:09

what about: complex& operator = (complex c) 1)if I define a copy-constructor, it will be called when I use: a=b; (right?!) 2) however if I use (a=b).method() it won't work because even if I return *this, the return value will be destroyed as soon as it is returned? - user2734408

@user2734408 complex& operator = (complex c) will work if u have copy ctor and do a = b. if u do (a=b).method() (y tu operator= tiene return *this at the end) it will work too. it will not be destroyed as soon as it is returned because when a ref goes out of scope no dtor is called. so it will work and call the function on a. so it will work fine but its not the normal way to do it i think - Kal

Actually, the pass-by-value is becoming the idiomatic version for operator=. It’s usually the superior variant. Look up “copy-and-swap” idiom. - Konrad Rodolfo

@KonradRudolph To me it seems like you are replacing something which is always good with something that is sometimes "only slightly worse". You could do the copy-and-swap if you choose to even if you pass by reference (by creating a third class as a copy and doing the swap). So really I see no advantage in passing by value, and a lot of disadvantages. - rabensky

@cluracan for copy and swap, it is always superior to accept the parameter by value because the compiler can use move-semantics, whereas if you take it by reference you cannot. however you and i dislike copy-and-swap anyway (as you say, replacing something that's always fine with something that's sometimes (most of the time?) worse) so its moot. EDIT - actually now that I think about it, copy and swap might be always equally fast and sometimes faster. but you have to write a swap function anyway so it's not really less work. - Kal

They aren't the same, the first one passes references so the objects remain in place in memory and the second will necesita 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.

Respondido el 26 de Septiembre de 13 a las 21:09

al 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.

Sin el & - your second example - you don't pass the same object, you pass a copia 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).

Respondido el 26 de Septiembre de 13 a las 21:09

sometimes it can be faster to make a copy (i.e. not use reference) but not usually. only for small classes i think - Kal

@kal yes, you are right. Using reference means you still have to copy the pointer itself - so it does take some time and some memory. If your object is smaller than a pointer then reference actually takes más, memory. Also, during the execution of the function, a reference adds a level of indirection so it takes longer than having the object on the stack. But these are considerations for more advanced needs :) - rabensky

Bueno, el punto completo of operator= is to make a copy. So passing by value is just fine (same comment as for Kal’s answer: look up the “copy-and-swap” idiom). - Konrad Rodolfo

@KonradRudolph - that would require an efficient swap, which not all object have or are able to have. In addition - it's still a tad slower as it requires a separate swap after the copy. Finally, if each instance of the class need a big chunk of data no matter what (that isn't shared for some reason) then you'll have a much larger memory imprint. So... no, that's not a superior method. - rabensky

@KonradRudolph also - if you do want to write the copy only once - write only operator= and use it in the copy constructor (by doing *this=other). It is much better than the other way around (as it doesn't require an efficient swap, and doesn't create 3 different objects) - rabensky

The second form takes and returns value by copy rather than by reference, which is often inefficient.

complex operator=(complex c);

El parámetro 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 previene esto.

Así que para resumir,

complex& operator=(const complex& c);

es la forma correcta.

Respondido el 26 de Septiembre de 13 a las 21:09

copy is not always less efficient - Kal

Same comment as for the other answers – look up the “copy-and-swap” idiom. Passing by value is usually entirely OK in the case of operator=, especialmente if the object is big (but can be swapped cheaply). In the case of a complex class, that’s probably not the case, though. - Konrad Rodolfo

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.