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:
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:
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:
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:
Solution to this problem: Would be better if the "swap" part was nothrow because copy assignment pointer cannot throw. Use pImpl Idiom.
FINAL SOLUTION:
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:
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:
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?
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:
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?
vector<T>::emplace_back
deal with exception safety?Copy Constructor:
Offers the strong guarantee
if the array is full (i.e. size == capacity), then:
Allocate new array
Copy objects over (copy constructor)
if a copy constructor throws:
destroy the new array
old array still intact
Strong guarantee
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:
Allocate new array
Move the objects over (move constructor)
if move constructor throws, then old array is no longer intact
Cannot offer strong guarantee anymore
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
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
Last updated