Improve exemple in canonical form notebook with some debug traces
Merged
requested to merge vrouvrea/gettingstartedwithmoderncpp:improve_canonical_operators_double_free_example into master
Compare changes
<div class="toc"><ul class="toc-item"><li><span><a href="#Assignment-operator" data-toc-modified-id="Assignment-operator-1">Assignment operator</a></span><ul class="toc-item"><li><span><a href="#Default-behaviour-(for-a-simple-case)" data-toc-modified-id="Default-behaviour-(for-a-simple-case)-1.1">Default behaviour (for a simple case)</a></span></li><li><span><a href="#The-pointer-case" data-toc-modified-id="The-pointer-case-1.2">The pointer case</a></span></li><li><span><a href="#Uncopyable-class" data-toc-modified-id="Uncopyable-class-1.3">Uncopyable class</a></span></li><li><span><a href="#Copy-constructor" data-toc-modified-id="Copy-constructor-1.4">Copy constructor</a></span></li><li><span><a href="#The-dangers-of-copy-constructions...-and-how-I-avoid-them" data-toc-modified-id="The-dangers-of-copy-constructions...-and-how-I-avoid-them-1.5">The dangers of copy constructions... and how I avoid them</a></span></li></ul></li><li><span><a href="#Canonical-form-of-a-class" data-toc-modified-id="Canonical-form-of-a-class-2">Canonical form of a class</a></span><ul class="toc-item"><li><span><a href="#[Advanced]-The-true-canonical-class" data-toc-modified-id="[Advanced]-The-true-canonical-class-2.1">[Advanced] The true canonical class</a></span></li></ul></li></ul></div>
```
```
```
```
```
```
```
```
```
So what's the deal? The default operator copies all the data attributes from `v1` to `v2`... which here amounts only to the `array_` pointer. But it really copies that: the pointer itself, _not_ the data pointed by this pointer. So in fine v1 and v2 points to the same area of memory, and the issue is that we attempt to free the same memory twice.
```
```
```
```
```
```
```
```
```
```
```
```
* More importantly, assignment operators may be a nightmare to maintain. Imagine you have a class for which you overload manually the assignment operator and/or the copy constructor. If later you add a new data attribute, you have to make sure not to forget to add it in both implementations; if you forget once you will enter the real of undefined behaviour... and good luck for you to find the origin of the bug!
* I define explicitly in my classes the behaviour of these operators with `= default` or `= delete` syntaxes. More often than not, my objects have no business being copied and `= delete` is really my default choice (this keyword indicates to the compiler the operator should not be provided for the class).
I don't pretend it is the universal choice, just my way to avoid the potential issues with manually overloaded copy operators (some would say the [Open-closed principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle) would avoid the most problematic one, but in the real world I find it difficult to stick with this principle...)
```
```
I admit it's a bit of boilerplate (and to be honest a script does the job for me in my project...), if you don't want to there are in fact rules that specify which of them you need to define: for instance if a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all three. See [this cppreference link](https://en.cppreference.com/w/cpp/language/rule_of_three) for more about these rules and [this blog post](https://www.fluentcpp.com/2019/04/23/the-rule-of-zero-zero-constructor-zero-calorie/) for an opposite point of view.