0

Can somebody please explain to me what this method / function is doing?

Bank& Bank::operator=(const Bank& bank) throw() {
    // Zuweisung auf mich selbst?
    if (this == &bank)
        return *this;
    // bisherige Konto-Objekte destruieren
    loescheKonten();
    // Attribute uebertragen und das Array anlegen
    this->name = bank.name;
    this->maxAnzKonten = bank.maxAnzKonten;
    kontoTab = new Konto*[maxAnzKonten];
    anzKonten = bank.anzKonten;
    // vorhandene Konten kopieren
    for (int i = 0; i < anzKonten; i++) {
        Konto* tmp = bank.kontoTab[i];
        kontoTab[i] = new Konto(*tmp);
    }
    return *this;
}

especially this :

Bank& Bank::operator=(const Bank& bank) throw() {
    // Zuweisung auf mich selbst?
    if (this == &bank)
        return *this;

what means Bank::operator=(const Bank& bank) ...

Bank constructor assigns the Bank class bank to the operator variable? or how? and operator is of type Bank?

Zong
  • 6,160
  • 5
  • 32
  • 46
MMMM
  • 3,320
  • 8
  • 43
  • 80
  • I heard you like banks – Salgar Dec 09 '13 at 16:05
  • It is a copy constructor: http://www.cplusplus.com/articles/y8hv0pDG/ – Rob Dec 09 '13 at 16:08
  • @Rob Um, no? It's an assignment operator. – BoBTFish Dec 09 '13 at 16:08
  • @Rob No. It is a copy-assignment operator, **not** a copy-constructor. – Zac Howland Dec 09 '13 at 16:09
  • The comment is pretty self explanatory (something like, test that we are not assigning the same instance of the object to itself..) It's an *optimization* that is sometimes added when you can't be too sure of how the object will be used... – Nim Dec 09 '13 at 16:10
  • @Nim In this particular case, the operator is dealing with dynamic memory, so the conditional check is not at all pointless. – Zac Howland Dec 09 '13 at 16:11
  • 5
    It is a pretty un-idiomatic implementation of an assignment operator. If something fails during assignment, then it leaver the asignee in some weird half-assigned state. Not good. Look at the [copy and swap idiom](http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom). – juanchopanza Dec 09 '13 at 16:11
  • Bist du ein Berliner? – Fiddling Bits Dec 09 '13 at 16:13

5 Answers5

4

This particular part is dealing with self-assignment. More often than not, it's a sign that the code in the assignment operator has problems such as lack of exception safety.

The typical case is when you have a class with dynamically allocated data, such as:

class X { 
    char *whatever;
    size_t size;
public:
    X &operator=(X const &other) { 
        delete [] whatever;
        size = other.size;
        whatever = new char [other.size];       
        for (int i=0; i<size; i++)
            whatever[i] = other.whatever[i];
    }
};

In the case of self-assignment, this will delete the data in the destination before copying the data in the source. If the source and destination are the same, deleting the data destroys the object.

To prevent that, it was at one time typical for this to include a condition at the beginning like you showed:

if (this == &other)
   return *this;

...so self-assignment didn't destroy your data. As noted above, however, this is unsafe in the face of exceptions. For exception safety, you typically want to create a copy of the source, then swap its contents into the destination. In such a case, having the check for self assignment can be included as an optimization, but is no longer necessary for correct operation (and at least in my experience, it's a fairly worthless optimization as well).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • As a rule of thumb, whenever creating the temporary object involves freestore allocation, its a useful optimization. – PlasmaHH Dec 09 '13 at 16:24
  • @PlasmaHH: My own experience is that it's really not. Self-assignment simply isn't common enough for the savings from avoiding dynamic allocation when it does happen to make up for testing for it all the other times. – Jerry Coffin Dec 09 '13 at 16:26
  • looks like our mileages vary. – PlasmaHH Dec 09 '13 at 16:30
  • @PlasmaHH If you use copy-swap, the extra conditional check adds a potential branch in your code. In many cases, that branch can be more expensive than copying the old data over top of your existing data. – Zac Howland Dec 09 '13 at 16:59
  • @ZacHowland: The freestore allocators I use are rather slow, and always worth quite a lot of branches. – PlasmaHH Dec 09 '13 at 17:00
  • @PlasmaHH Hence the *can be* note. It is all dependent on the platform you are dealing with, but I've seen cases where it was more expensive to be wrong with the branch prediction than it was to allocate a bit of space. – Zac Howland Dec 09 '13 at 17:04
3

This is a copy-assignment operator. The portion of code you are confused about is checking to make sure that the this pointer is not the same as the reference that was passed into the function. For example:

Bank b;
b = b;

The reference check prevents the second line from causing problems by trying to assign its data to itself (specifically, there is no need to reallocate dynamic memory when you are just setting yourself to yourself, so it avoids all of that).

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
1

Can somebody please explain to me what this method / function is doing?

It provides a particularly unsafe implementation for Bank class instances assignment. The implementation is unsafe because it can throw exceptions, while the function is marked as throw(). By default, if you run this code in low memory conditions (and an allocation fails) your application will call terminate and exit.

especially this :

Bank& Bank::operator=(const Bank& bank) throw() {
    // Zuweisung auf mich selbst?
    if (this == &bank)
        return *this;

what means Bank::operator=(const Bank& bank) ...

This declares a function that returns a Bank reference and takes a const reference to a Bank instance. The function is an assignment operation, which means you call it like this:

Bank a, b;
a = b; // same as a.operator=(b);

The if statement checks that the this pointer is not the same as the argument, as that is a case which would make the application experience undefined behavior.

utnapistim
  • 26,809
  • 3
  • 46
  • 82
0

the first theck prevents self assignment like so:

Bank a;
a = a;

The = operator is just like other class function but it's disguised as =. It will be called when inside of the expression a = b; both a and b are of type Bank.

This is what the definition means:

Bank& Bank::operator=(const Bank& bank); First Bank:: refers to the type of the left operand from a = b; and the argument const Bank& bank refers to b. It's just like any other function argument.

Also Bank& is the return value of the expression a = b and in this case it will return a If you want you don't need to return anything (using void) but in that case you will not be able to do a = b = c because b = c returns void and there is no equal operator for a = something_void

Raxvan
  • 6,257
  • 2
  • 25
  • 46
0

It basically overrides the = operator for objects of type Bank, allowing this:

Bank A;
Bank B;
.
.
.
A = B;  

The line

if (this == &bank)
    return *this;    

compares the pointer value of the parameter to the current instance, to see if they are the same object. If they are then there's no work to do, as you are assigning an object to itself.

The reason the method returns this as a non-const reference (Bank&) is because the following is valid c++ syntax when dealing with basic types (such as doubles, ints, chars):

(A = B) = C; //sic

....and it's considered good form to make your overridden operators behave as they would with basic types.

Grimm The Opiner
  • 1,778
  • 11
  • 29