> For the complete documentation index, see [llms.txt](https://lauradang.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lauradang.gitbook.io/notes/c++/cs_246/lecture-22.md).

# 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


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lauradang.gitbook.io/notes/c++/cs_246/lecture-22.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
