0

I’m doing an exercise in which I’m supposed to implement a copy-assignment operator for a class that looks as follows:

class Foo : public SuperFoo {
    Bar* fBar1;
    Bar* fBar2;
    ~Foo() {delete fBar1; delete fBar2;}
    // members without importance for the task.
};

The Bar class has the members Bar::Bar(const Bar&) and Bar& Bar::operator=(const Bar&) and is not polymorphic. In the suggested solution it proposes two implementations

Foo& Foo::operator=(const Foo& that)
{
    if (this != &that) {
        Bar* bar1 = 0;
        Bar* bar2 = 0;
        try {
            bar1 = new Bar(*that.fBar1);
            bar2 = new Bar(*that.fBar2);
        }
        catch (...) {
            delete bar1;
            delete bar2;
            throw;
        }
        SuperFoo::operator=(that);
        delete fBar1;
        fBar1 = bar1;
        delete fBar2;
        fBar2 = bar2;
    }
    return *this;
}

and

Foo& Foo::operator=(const Foo& that)
{
    SuperFoo::operator=(that);
    *fBar1 = *that.fBar1;
    *fBar2 = *that.fBar2;
    return *this;
}

The second is given that the pointers “doesn’t depend on one another”. What could this mean? I can see what is going on in the first implementation but I don’t understand when and why one would do it.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
user202542
  • 211
  • 1
  • 8
  • You could save yourself just about all the troubles you are having by using `std::unique_ptr` instead of `Bar*`. – François Andrieux Mar 07 '22 at 15:01
  • @FrançoisAndrieux: Guessing the basic structure of the class is out of their control; they do say the first block of code was given to them. – ShadowRanger Mar 07 '22 at 15:04
  • I'll note, option #2 is getting close to, but not quite, what [the copy-and-swap idiom](https://stackoverflow.com/q/3279543/364696) gets you. In real code, 99% of the time you'd want to avoid repeated code by implementing that idiom and having the compiler do most of the work, rather than worrying about whether there were dependencies between pointers, the possibility of self-assignment, whether you handle the case of a mid-copy exception properly, etc. – ShadowRanger Mar 07 '22 at 15:11
  • First implementation is atrocious for more than one reason. – Revolver_Ocelot Mar 07 '22 at 15:12
  • Thanks for your input guys. @Revolver_Ocelot Could you elaborate? – user202542 Mar 08 '22 at 06:33
  • (1) explicit check for self-assigment. You force everione to pay cost of something that will not happen. (2) if SuperFoo assigment operator throws, you leat 2 Bar pbjects, (3) if Bar destructor throws, you can leak memory, (4) if exception happens, object can be left in inconsistent state. And I am not even talking about manually handling everything instead of using tools designed to make programming easier and safer. – Revolver_Ocelot Mar 08 '22 at 07:47
  • @ShadowRanger What does dependencies between pointers mean in this case? – user202542 Mar 09 '22 at 19:30
  • @user202542: There are some unusual cases involving circular references between the `Foo` and its associated `Bar`s (I don't think the code as written can have them, but the unknown definition of `SuperFoo` could hide a lot). I suspect the real concern they're pointing out by saying "given that the pointers 'doesn’t depend on one another'" is the self-assignment case though; as written, if you do something like `myfoo = myfoo;` (usually less obvious than that, e.g. choosing a random index of an array and copying it to index 0, and you choose index 0), terrible things can happen. – ShadowRanger Mar 09 '22 at 20:03
  • See the link to the copy-and-swap idiom post I gave earlier for what it's protecting you from and how. – ShadowRanger Mar 09 '22 at 20:08

0 Answers0