100 likes | 153 Views
Idioms are reusable design techniques in a language We’ll look at 4 important ones in C++ Copy constructor trick for assignment Ensures release of existing resource and acquisition of the new resource both succeed or fail together RAII (a.k.a. Guard)
E N D
Idioms are reusable design techniques in a language We’ll look at 4 important ones in C++ Copy constructor trick for assignment Ensures release of existing resource and acquisition of the new resource both succeed or fail together RAII (a.k.a. Guard) ties dynamic resources to other (esp. automatic) scopes Reference counting ties dynamic lifetime to a group of references Copy-on-write allows more efficient management of multiple aliasing C++ Memory Management Idioms
Copy Constructor Trick for Assignment • Cleanup/assignment succeed or fail together class Array { public: Array(unsigned int) ; Array(const Array &); // assume copy constructor makes a deep copy ~Array(); Array & operator=(const Array &a); private: int * ints_; size_t size_; }; Array & Array::operator=(const Array &a) { if (&a != this) { Array temp(a); std::swap(temp.ints_, ints_); std::swap(temp.size_, size_); } return *this; }
C++11 Smart Pointers C++11 deprecates an older smart pointer template auto_ptr : can guard dynamically allocated memory and pass ownership around, but doesn’t work with the STL containers and has other limitations C++11 provides 3 new smart pointer templates instead shared_ptr : a general purpose reference counted guard for dynamic memory (we’ll mostly use this one in this course) weak_ptr : gives access to a resource that is guarded by a shared_ptr without increasing reference count (can be used to prevent memory leaks due to circular references) unique_ptr : a more complex but potentially very efficient way to transfer ownership of dynamic memory safely (implements C++11 “move semantics”)
Resource Acquisition Is Initialization (RAII) Also referred to as the “Guard Idiom” However, the term “RAII” is more widely used in C++ Relies on the fact that in C++ a stack object’s destructor is called when stack frame pops Idea: we can use a stack object to hold the ownership of a heap object, or any other resource that requires explicit clean up Initialize stack object when the resource is allocated De-allocate resource in the stack object’s destructor
RAII idiom example via shared_ptr class template #include <memory> using namespace std; shared_ptr<X> assumes and maintains ownership of aliased X Can access the aliased X through it (*spf) shared_ptr destructor calls delete on the pointer to the owned X when it’s safe to do so (per reference counting idiom discussed next) Combines well with other memory idioms shared_ptr<Foo> createAndInit() { Foo *f = new Foo; shared_ptr<Foo> p(f); init(f);// may throw exception return p; } int run () { try { shared_ptr<Foo> spf = createAndInit(); cout << “*spf is ” << *spf; } catch (...) { return -1 } return 0; } RAII Example: Guarding Newly Allocated Object
Basic Problem Resource sharing is often more efficient than copying But it’s hard to tell when all are done using a resource Must avoid early deletion Must avoid leaks Solution Approach Share both the resource and also a counter Each new reference increments the counter When a reference is done, it decrements the counter When count drops to zero, delete resource and counter “last one out shuts off the lights” Introduction to Reference Counting reference reference Resource reference counter == 3
RAII idiom example via shared_ptr class template #include <memory> using namespace std; shared_ptr<X> assumes ownership of aliased X shared_ptr<X> copy constructor increases count, and its destructor decreases count shared_ptr destructor calls delete on the pointer to the owned X when count drops to 0 shared_ptr<Foo> createAndInit() { Foo *f = new Foo; shared_ptr<Foo> p(f); init(f);// may throw exception return p; } int run () { try { shared_ptr<Foo> spf = createAndInit(); shared_ptr<Foo> spf2 = spf; // object destroyed after // both spf and spf2 go away } catch (...) { return -1 } return 0; } Reference Counting Example: Sharing an Object
Basic Problem Reference counting enables safe and efficient sharing But what if modifications are made to the resource? May want logically separate copies of resource Solution Start with reference counting Writer checks for count > 1 Copies reference & counter Updates both counters Performs the write Readers all share a copy, each writer can get its own Introduction to Copy on Write write() Resource 2 reference counter == 1 Resource reference counter == 2 reference
Know what goes where in memory Understand mechanics of stack and heap allocation Watch for simple (and complex) lifetime errors Think about shallow copy vs. deep copy (problems and performance trade-offs) Master useful idioms for C++ memory management Learn how they work Understand when to apply them Look for ways to apply them in the labs and beyond C++11 smart pointers (especially shared_ptr) very helpful Summary: Memory Management Tips