- Want our program to recover from exceptions
- Program to not leak memory
- Want to stay in a consistent state (no dangling ptrs, no broken invariants)
- C++ guarentee: during stack unwinding all stack allocated objects are destroyed, destructors run and memory is reclaimed
Old f method
void f() {
MyClass *p = new MyClass();
MyClass m;
g(); // g() might throw an exception
delete p;
}
Refactor f method
void f() {
MyClass *p = new MyClass();
try {
MyClass m;
} catch (...) {
delete p;
throw;
}
delete p;
}
- But this code is super complex, tedious, and very error prone
- Want a way to guarantee that some code runs irrespective of whether an exception occurs or not
Language | Mechanism |
---|---|
Java | finally |
Scheme | dynamic-wind |
C++ | nothing |
- in C++, we need to rely on the guarantee for stack objects
- Maximize stack usage
- Every resource should be wrapped within a stack allocated object whose destructor released the resource
int main() {
ifstream f{"file.txt"}; // automatically opens the file
}
- The file resource is released (closed) when the stack object goes out of scope
- Wrap the heap object within a stack object whose destructor deallocates the heap object
- STL provides a template class to do this
std::unique_ptr<T>
- Constructor takes a T* as an argument
- destructor deletes the ptr
- overloads operator*, operator->
void f() {
std::unique_ptr<MyClass> p{new MyClass};
// auto p = std::make_unique<MyClass>();
MyClass m;
g();
// Don't need to delete p since it is stack allocated and will clean the heap allocated MyClass up
}
- TODO:
c++/unique_ptr/example1.cc
class c{...};
auto p = make_unique<c>();
std::unique_ptr<c>;
unique_ptr<c> q = p; // won't compile
unique_ptr
does not have a copy constructorunique_ptr
cannot be copied as then you would have multiple stack objects pointing tot he same heap object- double
delete
will get called
- double
- Sample implementation of
unique_ptr
TODO:
c++/unique_ptr/basicimpl.cc
- Note that
void f() = delete;
disables methodf()
- Who owns the heap resource
- If code does not own the heap resource, it can be provided the "raw" pointer
- Use
get()
to access the raw ptr
- Use
- If there are multiple owners, use
std::shared_ptr
void g() {
std::shared_ptr<MyClass> p1 = make_shared<MyClass>();
if () {
auto p2 = p1; // copy constructor
} // p2 goes out of scope (won't deleted MyClass object as p1 still points to it)
} // p1 out of scope, destructor will delete MyClass ptrs
shared_ptr
uses reference counting- destructor only deletes heap memory when ref count reaches 0
- Basic Guarantee: if an exception occurs the program is in a valid but unspecified state (no memory leaks, no dangling ptrs, etc.)
- Strong Guarantee: if an exception occurs during f, it is as if f was never called
- No-throw Guarentee: f does not throw exceptions, achieves its task