# Lecture 22

## Ownership

* Owning the resource = `unique_ptr` **(OWNS-A)**
* Not owning the resource = `raw ptr` **(HAS-A)**
* Shared ownership? This is very rare `shared_ptr`

## Shared\_ptr

**Example of shared\_ptr**:

```
{ 
  auto p1 = std::make_shared<MyClass>();
  if (...) {
    auto p2 = p1;
  } // p2 popped, pointer not deleted
} // p1 popped, pointer deleted
```

* Shared ptrs maintain a **reference const**

#### Reference const

* Count of all shared\_ptrs pointing at the same object
* Memory is freed when the # of shared\_ptrs pointing to it is about to reach 0
* Shared pointers have their own destructors (don't need to write one) - so you don't need to worry about double freeing in a list when you have shared ownership

#### Downsides of shared\_ptrs

**Do not do this:**

```
// Two different reference counts for the same object 
// Made two shared_ptrs on 1 obj
C *p = new C;
shared_ptr<C> p1 {p};
shared_ptr<C> p2 {p};

// do not point a shared_ptr to another shared_ptr (you will create a cycle)
```

## Exception Safety Ctd.

3 levels of exception safety for a function f:

#### 1. Basic Guarantee

* if an exception occurs: program will be left in some **valid state**
* no leaks
* no corrupted data structures
* class invariants maintained

#### 2. Strong Guarantee (you want this most often)

* if an exception is raised while executing f: state of program will **be as it was before it was called**

#### 3. No Throw Guarantee

* f will never throw or propogate an exception
* f will always accomplish its task

**Example of Exception Safety**:

```
class A {...};
class B {...};
class C {
  A a;
  B b;
  public:
    void f() {
      a.g(); // May throw (strong guarantee)
      b.h(); // May throw (strong guarantee)
    }
};
```

**Question**: Is `C::f`'s exception safe? **Answer**: Analyze what each statement throws:

* if a.g() throws:
  * Nothing in the program has happened yet
  * **Conclusion**: This is **OK**
* if b.h() throws:
  * Effects of g must be undone to offer the strong guarantee
    * Very hard or impossible if g has non-local side-effects
  * **Conclusion**: Probably not exception safe

*So what if A::g and B::h **do not** have non-local side-effects?*

**Answer**: We can use `copy-and-swap` as such:

```
class C{
  ...
  void f() {
  // if any of these lines throw, the original a and b would still be intact
  A atemp = a;
  B btemp = b;
  atemp.g();
  btemp.h();
  a = atemp; // copy assignment throws
  
  // if this line throws, a has changed, so state is no longer intact - this is no longer strong guarantee
  // the copy assignment throws here too (aka the swap part)
  b = btemp;
  }
}
```

**Solution to this problem**: Would be better if the "swap" part was nothrow because copy assignment pointer cannot throw. **Use pImpl Idiom.**

**FINAL SOLUTION**:

```
// This results in a STRONG GUARANTEE - what we want!
struct CImply {
  A a;
  B b;
};

class C {
  unique_ptr<CImpl>pImpl;
  ...
  void f() {
    auto temp = make_unique<CImpl> (*pImpl);
    
    // if the following 2 lines throw, original a and b are still intact - Yay!
    temp->a.g();
    temp->b.h();
    std::swap(pImpl, temp); // No throw
  }
}
```

### Exception Safety and the STL: vectors

#### How do vectors deal with exception safety?

* Encapsulate a heap-allocated array
  * Follows RAII
    * When a stack-allocated vector goes out of scope, the internal heap-allocated array is freed

**Example of Exception Safety with Vector that's good**:

```
void f() {
  vector<MyClass> v;
  ...
}
```

**What's happening in the code above?**

* v goes out of scope
* Array is freed
* MyClass destructor runs on all objects in the vector
* everything is all good :)

**Example of Exception Safety with Vector of pointers that's not so good**:

```
void g() {
  vector <MyClass *> v;
  ...
}
```

**What's happening in the code above?**

* v goes out of scope
* Array is freed
* Pointers don't have destructors though, so any objects pointed at by the pointers **are not deleted** resulting in **MEMORY LEAK**
* v doesn't know whether the pointers in the array **own** the objects they point at

So why can't you fix this problem by writing this?

```
for (auto p:v) delete p // this would work, but it's not proper design
```

If you need to do this, that means the pointer **Own** the objects they point at, and if you just use unique\_ptrs, then the deleting would happen by itself.

**Example to a vector of pointers that's good**:

```
void h() {
  vector <unique_ptr<MyClass>> v;
  ...
}
```

**What's happening in the code above?**

* v goes out scope
* Array is freed
* unique\_ptr destructor runs, so the objects **are deleted**
* No need for **any** explicit deallocation

### How does `vector<T>::emplace_back` deal with exception safety?

#### Copy Constructor:

* Offers the **strong guarantee**
  * if the array is full (i.e. size == capacity), then:
    1. Allocate new array
    2. **Copy** objects over (copy constructor)
       * if a copy constructor throws:
         * destroy the new array
         * old array still intact
         * **Strong guarantee**
    3. Delete old array (no throw)

However,

* Copying is expensive and the old data will be thrown away
* Wouldn't moving the obejcts be more efficient?

#### Move Constructor:

* if the array is full (i.e. size == capacity), then:
  1. Allocate new array
  2. **Move** the objects over (move constructor)
     * if move constructor throws, then old array is no longer intact
     * **Cannot offer strong guarantee anymore**
  3. Delete old array

**What if move constructor offers the nothrow guarantee?**

* Emplace\_back will use the move constructor
* Otherwise it will use the copy constructor - this is **slower**

So your move options should offer the nothrow guarantee, and you should indicate that they do!

**Note**: pointer op, pointer assignments, delete will never throw

```
class MyClass {
  public:
    ...
    MyClass(MyClass &&other) noexcept {...}
    MyClass &operator=(MyClass &&other) noexcept {...}
};
```

**Note**: If you know a function will never throw or propogate an exception, declare it noexcept, facilitates optimization. At minimal, moves and swaps should be noexcept
