Download presentation
Presentation is loading. Please wait.
Published byEliza Cottam Modified over 9 years ago
1
. Smart Pointers
2
Memory Management u One of the major issues in writing C/C++ code is managing dynamically allocated memory u Biggest question is how to ensure that allocated memory will be freed when it is no longer in use
3
Strategy #1: Fixed Ownership u Allocated pointer belongs to the entity (function or objects) that created it u That entity is responsible for freeing the pointer void foo() { char* mem = new char[1000]; … delete [] mem; }
4
Example: String class class String { public: String( char const *str ) { int l = strlen(str); m_data = new char[l]; memcpy(m_data, str, l); } ~String() { delete [] m_data; } private: char* m_data; }; The memory for char* represented by String is owned by the object u Class encapsulates details of memory management u With careful implementation, this class is memory-tight
5
Strategy #2: Dynamic ownership (compile time) u Object has an owner u However, owner changes through specific function calls Example: u strdup(s) allocates new memory and transfers it with return value u strdup does not release the memory
6
Ownership transfer and interface design Design principle: u keep free resources at the same level you allocate them u Reduces memory leaks due to interface problems
7
Example: design choices ReadLine – read a line of input u char* ReadLine() – returns pointer to newly allocated memory – user has to free it u char* ReadLine() – returns pointer to static buffer – user has to copy line to another buffer u void ReadLine(char* Buffer) – uses a user supplied buffer – ReadLine cannot resize buffer
8
Strategy #3: Dynamic ownership (run time) u In some case we cannot know who will own a pointer u In other cases, we do not want the programmer to remember who owns what u Can we use an object that “remembers” who owns the object?
9
Dumb Pointers u Suppose T is a class u T* is a “dumb pointer” supplied by compiler u It remembers the address of the object and allows us to access it, but nothing else u Can we build smarter pointers?
10
The Pointer Interface To implement a pointer-like object we need: u pointer::pointer( T*) u pointer::pointer( pointer const& ) u pointer& operator=( pointer const& ) u T& pointer::operator*() u T const& pointer::operator*() const u T* pointer::operator->() u T const * pointer::operator->() const u pointer::operator void const*() const
11
Pointer class template class pointer { public: pointer( T* p = NULL ) : m_ptr(p) {} T& operator*() { return *m_ptr; } … private: T* m_ptr; };
12
“Smart” Pointers u We can ensure that pointer “cleans up” after itself u Simply add destructor pointer::~pointer() { if( m_ptr != NULL ) delete m_ptr; } This class is called auto_ptr
13
Auto_ptr struct bar { … }; void foo() { auto_ptr myBar = new bar; … // use myBar as a pointer … } // myBar is deleted automatically
14
Auto_ptr in exceptions u Auto_ptrs provide clean mechanism to deal with exception void foo() { auto_ptr myBar = new bar; apple(); // apple might throw an execption … } // myBar is deleted automatically // even if an exception is thrown by apple
15
Auto_ptr auto_ptr is like a pointer, but not exactly: void foo() { auto_ptr myBar = new bar; … if( … ) { auto_ptr myOtherBar = myBar; … } … } What happens in this example?
16
Transfer of Ownership u To avoid multiple deletes, auto_ptr ensures that only one auto_ptr points to a certain object u The statement auto_ptr myOtherBar = myBar; transfer the ownership from myBar to myOtherBar How do we achieve this?
17
auto_ptr details auto_ptr( auto_ptr& rhs ) : m_ptr( rhs.release() ) {} auto_ptr& operator=( auto_ptr& rhs ) { reset( rhs.release() ); return *this; } void reset(T* p = NULL) { if( m_ptr != p ) delete m_ptr; m_ptr = p; } T* release() { T* tmp = m_ptr; m_ptr = NULL; return tmp; }
18
Auto_ptr summary u Provide mechanism for transfer of ownerships u Can be dangerous u Requires discipline from programmer u Does not replace the need for pointers The method T* auto_ptr ::get() allows to access the dumb pointer version of an auto_ptr
19
Strategy #4: Reference Counting u In some cases, we do not want to establish ownership u Managing ownership within forces us to make unnecessary copies u Can we get away with memory management without authorship? u The general mechanism of reference counting provides one solution
20
Reference Counting String a = “foo bar”; String b = a; String c = a; The resulting memory structure: foo bar a: b: c: stackheap
21
Reference counting u Can we do better? Idea: Do not copy value of string u Have all object point to the same memory u How do we know when to free the memory? foo bar a: b: c:
22
Reference Counting Solution: u Store a reference counter that counts number of pointers u Reference counter shows whether the object is in use a: b: c: 3 foo bar
23
Reference Counting 1 After Object Creation 1 1 After Object Destruction 3 0 After Last Object Destruction 4 2 After Object Copy 2
24
String with reference counting u See [String.h]
25
Example revisited Returning to the ReadLine example u String ReadLine() returns a String object A new String is copied on return value But… the actual memory is not copied Ownership transfer occur smoothly with minimal overhead
26
ReadLine Example String ReadLine() { String line; … // do read return line; } void foo() { String a = ReadLine(); … }
27
General Purpose Reference Counting u See RCPointer.h
28
Reference Counting u Suppose String has operator[] u Consider the following code String a = “foo bar”; String b = a; String c = a; c[2] = ‘l’; u What does this code do?
29
Reference Counting u After we modify c, it is no longer identical to a and b u We can no longer save memory by storing all three strings in one place Solution u “Clone on Write” – make a copy of an object when it is modified
30
Implementing operator[] in String Read-only access: char const& operator[](int i) const { return m_ptr->m_data[i]; } Read/Write access: char & operator[](int i) { if( m_ptr->m_rc > 1 ) { // make a new copy of the string m_ptr->m_rc--; m_ptr = new StringValue( *m_ptr ); } return m_ptr->m_data[i]; }
31
Clone on Write u Perform the copy operation only when new copy is needed u This is an instance of “lazy evaluation” u How can we perform this in a generic RCPointer?
32
Template Clone on Write Distinguish between u read only access: T const& RCPointer ::operator*() const; T const* RCPointer ::operator->() const; u and read/write access T& RCPointer ::operator*(); T* RCPointer ::operator->(); In these operations we perform copy
33
Reference counting and cycles u Reference counting could have been used as an automatic garbage collection in C++. u Problem: Data structures can include cycles. In this case the pointers will never be deleted. If all these pointers were reference counted, then no memory would be freed
34
When to use what ? u auto_ptr/Ownership transfer: simple yet problematic. Good for local variables u Reference counting: Simple, memory safe, efficient, problematic when modifying the object. Very good for large objects, and STL containers providing these do not change the objects. u Reference counting with Clone On Write: Optimal for STL, and for large objects. problematic for data structures with cycles.
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.