Thanks. I ended up reading several more pages into the book and it explained this exact scenario. I'll try to give an explanation in case anyone has the same question.
The issue is that is the assignment operator won't work correctly if the object is assigned to itself:
1 2
|
HasPtr ptr;
ptr = ptr;
|
If the object is assigned to itself, the parameter
hp
and
this
in the copy assignment operator both point to the same location in memory.
For the sake of this example, let's define the constructor slightly differently, with text this time...
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
class HasPtr {
public:
HasPtr(const std::string &s = std::string("Hello World")) : ps(new std::string(s)), i(0) { }
HasPtr& operator=(const HasPtr &hp) { // copy assignment operator
std::string *new_ps = new std::string(*hp.ps);
delete ps;
this->ps = new_ps;
i = hp.i;
return *this;
}
private:
std::string *ps;
int i;
};
|
If the object is assigned to itself,
this
and
hp
will point to the same location in memory. Therefore
this.ps == hp.ps
evaluates to true. By deleting
ps
in line 6, which is also equivalent to
this->ps
, we are also implicitly deleting
hp.ps
because they both refer to the same object. Therefore, after calling delete on
ps
,
*hp.ps
is now undefined because it was just implicitly deleted.
So if we used this code...
1 2 3 4 5 6
|
HasPtr& operator=(const HasPtr &hp) { //copy assignment operator=
delete ps; // memory is freed at location that both ps AND hp.ps are pointing too
ps = new std::string(*hp.ps); //*hp.ps is undefined because hp.ps was just deleted
i = hp.i;
return *this;
}
|
...We can see how allocating and assigning a new string to
ps
is dangerous;
*hp.ps
is undefined and therefore so will
*ps
.