1

I am searching for an answer to the following explaination (from the book "A tour of C++")

MyClass& operator=(const MyClass&) // copy asignment: clean up target and copy

I've never cleaned up a target (or at least I don't get what does it mean) when copying so:

  • The ideea of copying isn't that of having two identical things?
  • If i clean up the target, wouldn't that be a move?
  • What exactly is meant by clean up target?

    • the reference is also const so I wouldn't be able to modifying it

Below in the book it states:

MyClass& operator=(MyClass&&) // move assignment: clean up target and move

Here it makes sense to clean up target as this is how I understand the move -ing thing works

Cătălina Sîrbu
  • 1,253
  • 9
  • 30
  • 4
    That target is the object the operator is called on, not the argument passed – Mat Apr 17 '20 at 19:37
  • 2
    Presumably they mean to clean up/free any resources owned by the object being assigned _to_ before copying them from the object being assigned from. – Miles Budnek Apr 17 '20 at 19:41
  • 3
    Probably means that you remove the old remnants of the current object (such as allocated memory) before the copying happens. But this is bad advice anyway, since an assignment operator is flawed if you start changing the values of `*this` before the copying is completed without throwing an exception. What is usually done is `copy / swap`, where you use a temporary copy of the passed-in object and do simple `std::swap's` on the members of `this` and the temporary. – PaulMcKenzie Apr 17 '20 at 19:42
  • ok so far I the only thing I get is that I misunderstood **which is the target**. The target here `obj_A = B` would be `obj_A`? – Cătălina Sîrbu Apr 17 '20 at 19:43
  • 1
    The target is the value on the left-hand-side of the `=`. – PaulMcKenzie Apr 17 '20 at 19:44
  • Copying takes place from *source* to *target*. Target is another word for destination, or in this case the current object itself. – rustyx Apr 17 '20 at 19:44
  • 1
    Additional info: https://en.cppreference.com/w/cpp/language/copy_assignment – R Sahu Apr 17 '20 at 19:44
  • @PaulMcKenzie with the _current object_ do you refer to the target (_destination_)? – Cătălina Sîrbu Apr 17 '20 at 19:45
  • Yes. `*this` is the destination object. – PaulMcKenzie Apr 17 '20 at 19:47
  • @PaulMcKenzie I would like to know more about what you've written about the copy/swap thing, if you could give me some reading material it would be grate – Cătălina Sîrbu Apr 17 '20 at 19:48
  • 1
    He's referring to [the copy-and-swap idiom](https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom) Often it isn't the most optimal way to perform copy assignment but it is quick, and easy and it's nearly impossible to get wrong under any circumstances. I start with copy-and-swap and migrate to something faster if profiling says I need the extrra speed. I almost never do. – user4581301 Apr 17 '20 at 19:51
  • @CătălinaSîrbu -- Yes. The trick is to implement the copy constructor and destructor first. Once both of those functions are working flawlessly, as user4581301 says, it's virtually impossible to write an incorrect assignment operator using `copy / swap`, since it is just rote `std::swap` calls of all the object's members. – PaulMcKenzie Apr 17 '20 at 19:54

1 Answers1

2

Suppose MyClass has an owning pointer

class MyClass {
  Owned *that;
public:
...
  MyClass& operator=(const MyClass&other) // copy asignment: clean up target and copy
  {
     Owned = other->owned;
  }

What happens with the memory that pointed to? it is leaked. So instead do

  MyClass& operator=(const MyClass&other) // copy asignment: clean up target and copy
  {
     if (this == &other)  // prevent self assignment as this would in this case be a waste of time.
       return *this;
     delete that; // clean up
     that = new Owned(*other->that); // copy
     return *this; // return the object, so operations can be chained.
  }

Better thanks to @PaulMcKenzie && @Eljay

  MyClass& operator=(const MyClass&other) // copy asignment: clean up target and copy
  {
     Owned *delayDelete = that;
     that = new Owned(*other->that); // copy, if this throws nothing happened
     delete delayDelete; // clean up
     return *this; // return the object, so operations can be chained.
  }
Surt
  • 15,501
  • 3
  • 23
  • 39
  • Wow, it was quite simple. Thanks – Cătălina Sîrbu Apr 17 '20 at 19:54
  • 2
    Your code has the flaw I mentioned in my comments. You delete `that` before you allocated memory. What if `new` throws an exception? Or `Owned` is a class that can throw on construction? – PaulMcKenzie Apr 17 '20 at 19:59
  • Some extra reading on the subject: [The Rule of Three/Five/Zero](https://en.cppreference.com/w/cpp/language/rule_of_three). What you want to strive for is using the Rule of Zero as often as possible. This means that direct owners of resources need to support Three or Five and everyone else does absolutely nothing, the resource holder and the compiler do all the work for them. – user4581301 Apr 17 '20 at 20:00
  • @PaulMcKenzie just know I understand what you've told me in your answer earlier... – Cătălina Sîrbu Apr 17 '20 at 20:00
  • Preventing the self-assignment check can be taken out. The routine is self-assignment correct, which is even better. – Eljay Apr 17 '20 at 20:13
  • what is that `delayDelete`? could you please explain ? – Cătălina Sîrbu Apr 17 '20 at 20:30
  • Surt is keeping the original object at `that` around in so that he can `delete` it later if nothing goes wrong. Note that with copy-and-swap, this function could be as simple as `MyClass& operator=(MyClass other) {std::swap(that, other.that); return *this; };` I don't bother with self assignment because I'm a snob and consider self-assignment a programming error on the part of the assigner, not the assignee. If it's happening often enough to worry about the performance hit, you're probably doing something stupid. – user4581301 Apr 17 '20 at 20:50
  • @user4581301 self assign check is also a drag on performance if not absolutely needed. – Surt Apr 18 '20 at 10:01