TDDD38 APiC++ Smartpointers 317
Smart pointers
A smart pointer stores a pointer to another object. ¥ simplifies resource management Ð can prevent memory leaks if exceptions are thrown Ð can help ensure that resources are available as long as they are needed, and disposed of when no longer needed ¥ strong and weak references Ðastrong reference protects the referenced object from garbage collection Ð an object referenced only by weak references is considered unreachable and may be collected at any time ¥ C++ provide strong/weak reference functionality for pointers Ð include
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 318 unique_ptr (1)
¥ retains sole ownership of an object through a pointer and destroys that object when the unique_ptr goes out of scope
template
{//some block unique_ptr
unique_ptr
unique_ptr
unique_ptr
¥ will dispose of the pointed-to object when destroyed itself Ð for example when leaving block scope Ð this is done with an associated deleter ¥ typical uses Ð providing exception safety by deleting dynamically allocated objects on both normal exit and exit through exception Ð transferring ownership of uniquely-owned objects with dynamic lifetime into functions (argument passing) Ð acquiring ownership of uniquely-owned objects with dynamic lifetime from functions (return value) Ð as the element type in move-aware containers, such as std::vector, which hold pointers to dynamically-allocated objects
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 319 unique_ptr (2)
¥ constructors
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr up5{ std::move(up4) }; // type converting constructor Ð ownership is transferred
Ð there is also a constructor for passing an auto_ptr smart pointer (C++98, deprecated in C++11) Ð there are also versions taking a deleter ¥ destructor Ð deletes the owned object ¥ assignment
up1 = std::move(up2); // move assignment Ð up2 becomes nullpointer
up1 = nullptr;//becomes as if default initialized
up1 = std::move(up5); // type converting assignment, also the deleter will be converted
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 320 unique_ptr (3)
¥ observers
cout << *up << endl; // up must not be nullptr
cout << up->memfun() << endl; // up must not be nullptr
cout << up.get()->memfun() << endl; // get() returns the stored pointer
cout << up2[i] << endl; // array version elements are indexable
if (up) cout << up->memfun() << endl; // true if stored pointer is not nullptr
unique_ptr
¥ modifiers
Object* p{ up.release() }; // sets up to nullptr
up.reset(p); // assigns new pointer, and then calls the deleter for the old pointer, if not nullptr
up1.swap(up2); // swaps pointers and deleters Ð also non-member version
up.reset(new int(2)) // assigns new pointer, and then calls the deleter for the old pointer
¥ comparisons Ð memory locations compared == != < <= > >=
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 321
Standard library default deleters
¥ the single object deleter calls delete on the stored pointer Ð defined as primary template
template
template
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 322
Shared-ownership pointers
¥ Implements semantics of shared ownership Ð stores a pointer, usually obtained via new Ð the last remaining owner of the pointer is responsible for destroying the object, or Ð otherwise releasing the resources associated with the stored pointer ¥ Two associated smart pointer types Ð shared_ptr Ð weak_ptr
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 323 shared_ptr
¥ a shared_ptr object can take ownership of a pointer and manage the storage of that pointer
shared_ptr
Ð provide a limited garbage-collection facility ¥ shared_ptr objects can share ownership
shared_ptr
Ð the group of owners becomes responsible to delete the pointer when the last of them releases ownership ¥ shared_ptr objects can only share ownership by copying their values Ð two shared_ptr objects constructed from the same (non-shared) pointer will both own the pointer without sharing it
int* p = new int{ 4711 }; shared_ptr
Ð if one such shared_ptr releases the pointer, deleting the managed object, leaves the other pointing to an invalid location ¥ ownership is released as soon as a shared pointer object is Ð destroyed Ð changed by an assignment Ð changed by a call to reset() if the use count is 1 when this happens, the managed pointer is deleted
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 324
Inside shared_ptr
shared_ptr object
control block
(on heap) use count: 1 (strong count)
weak count: 0
(on heap)
¥ if several shared_ptr shares ownership of object they will also share the control block Ð use count (strong count) stores the number of strong references, i.e. shared_ptr, referring to object Ð weak count stores the number of weak references, i.e. weak_ptr, referring to object (none above)
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 325 shared_ptr operations (1)
¥ constructors
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
Ð aliasing constructor Ð example later ¥ destructor Ð if use count is greater than 1, the use count of the other objects sharing ownership is decreased by 1 Ð if use count is 1 (last referrer) the owned object is deleted Ð if use count is 0 (empty shared_ptr) the destructor has no side effects
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 326 shared_ptr operations (2)
¥ assignment
sp1 = sp2; // copy assignment – add sp1 as a shared owner to sp2’s assets
sp1 = std::move(sp2); // move assignment Ð transfer ownership from sp2 to sp1, sp2 becomes empty
sp1 = std::move(up); // move from unique_ptr (or auto_ptr) Ð ownership is transferred, use count set to 1
sp1 = nullptr;//managed pointer is deleted, since use count is 1 Ð sp1 becomes empty
Ð a call to an assignment operator has the same effect as if the shared_ptr destructor was called before the value is changed, including the deletion of the managed object if use count was 1 (pointer was unique) Ð the value of a pointer cannot be assigned directly to a shared_ptr object
sp1 = std::make_shared
sp1.reset(new int{ 17 });
Ð a call to reset() has the same effect as if the shared_ptr destructor was called before the value is changed
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 327 shared_ptr operations (3)
¥ comparisons Ð memory locations comapred == != < <= > >=
sp1 == sp2 // returns sp1.get() == sp2.get()
sp1 < sp2 // returns sp1.get() < sp2.get()
sp == nullptr // returns !sp
¥ observers
p = sp.get(); // the stored pointer is returned (not the owned pointer if sp is aliased)
cout << *sp; // operator* returns a reference to the object pointed by the stored pointer
cout << sp->mem; // operator-> returns a pointer to the object pointed by the stored pointer
long n = sp.use_count(); // number of shared_ptr sharing ownership over the same pointer as sp
if (sp.unique())… // true if sp is sole referrer
if (sp)… // operator bool returns true if sp is not a null pointer
if (sp1.owner_before(sp2))… // …
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 328 shared_ptr operations (4)
¥ modifiers
sp1.swap(sp2); // exchange content of sp1 and sp2 Ð transferring ownership, keeping use count swap(sp1, sp2); // non-member, ditto
sp1.reset(); // sp1 becomes empty (as if default-constructed) Ð if unique managed object is deleted sp1.reset(p); // sp1 acquire ownership of pointer p Ð if unique the previously managed object is deleted
sp2.reset(sp1.get()); // equivalent to shared_ptr(sp1.get()).swap(sp2)
cout << sp1 << ’\n’; // writes a system-specific textual representation of the stored pointer value
¥ shared_ptr creation
auto sp = std::make_shared
¥ shared_ptr casts Ð static_pointer_cast(sp) returns a copy of sp with the stored pointer converted to U* (compatible by static_cast) Ð dynamic_pointer_cast(sp) returns a copy of a sp with the stored pointer converted to U* (compatible by dynamic_cast) Ð const_pointer_cast(sp) returns a copy of a sp with the stored pointer converted to U* (compatible by const_cast) ¥ there is more…
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 329 weak_ptr
A weak_ptr object stores a weak reference to an object that is already managed by a shared_ptr.
shared_ptr
weak_ptr
¥ must be converted to shared_ptr in order to access the referred object
sp = wp.lock();
¥ models temporary ownership Ð when an object needs to be accessed only if it exists, and it may be deleted at any time by someone else, weak_ptr is used to track the object, and it is converted to std::shared_ptr to assume temporary ownership Ð if the original shared_ptr is destroyed at this time, the object’s lifetime is extended until the temporary shared_ptr is destroyed as well ¥ used to break cycles in data structures Ð dashed pointer is weak, the others are strong
Ð each object must contain both a shared_ptr and a weak_ptr Ð only one at a time is used
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 330 weak_ptr operations (1)
¥ constructors
weak_ptr
weak_ptr
weak_ptr
¥ destructor Ð destroys the weak_ptr object but has no effect on the object its stored pointer points to ¥ assignment
wp1 = wp2; // copy assignment
wp = sp; // shared_ptr objects can be assigned to weak_ptr objects directly, but
sp = wp.lock(); // assigning a weak_ptr object to a shared_ptr must be done using member lock()
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 331 weak_ptr operations (2)
¥ modifiers
wp1.swap(wp2); // exchanges the contents, swapping their owning groups and any stored data
swap(wp1, wp2); // non-member swap, ditto
wp.reset(); // wp becomes empty, as if default constructed
¥ observers
long n = wp.use_count(); // number of shared_ptr objects that share ownership over the same pointer as wp
if (wp.expired())… // true if wp is empty or no more shared_ptr in the owner group wp belong to
sp = wp.lock(); // returns: expired() ? shared_ptr
if (wp1.owner_before(wp2))… // …
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 332 shared_ptr and weak_ptr
shared_ptr
weak_ptr
{ shared_ptr
if (p2) // check to see if p2 is not a null pointer { …//do something with object referred by p2 } }//p2 is destroyed Ð p1 becomes sole owner to the pointer
p1.reset(); // memory is deleted Ð p1 is set to null pointer
shared_ptr
if (p3) { …//will not be executed }
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 333
Inside shared_ptr and weak_ptr
shared_ptr
1
weak_ptr 1
¥ when a shared_ptr is first created, an additional control block is created on the heap Ð strong count is set to 1, weak count to 0 ¥ each time a copy of a shared_ptr is made, or created from a weak_ptr, strong count is incremented Ð when a shared_ptr is destroyed, strong count is decremented ¥ each time a weak_ptr is made, from a shared_ptr or a weak_ptr, weak count is incremented Ð when a weak_ptr is destroyed, weak count is decremented ¥ when the last shared_ptr is destroyed, the referred object is deleted Ðifweak count > 0 Ð the pointer in the control block is set to null, and strong count to 0 Ð remaining weak pointers have expired Ðifweak count is 0 Ð also control block is destroyed
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 334 shared_ptr aliasing (1)
A shared_ptr object can share ownership over a pointer while at the same time point to another object Ð aliasing. ¥ the aliasing constructor takes a shared_ptr (r) and another pointer (p)
template
Ð sp.get() == p Ð sp.use_count() == r.use_count() ¥ commonly used to point to member objects while owning the object they belong to (figure on next slide)
using Object_vector = vector
shared_ptr
store->push_back(Object()); // store a couple of objects store->push_back(Object());
shared_ptr
shared_ptr
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 335 shared_ptr aliasing (2)
The code example on previous slide will result in the following:
store:
3
0
sp1:
sp2:
¥ store, sp1 and sp2 shares ownership of the pointer to the vector ¥ sp1 and sp2 points to a corresponding Object in the vector, but does not own that pointer
store.reset();
¥ use count is 3 when reset() is called Ð the managed vector is not deleted Ð use count is decreased to 2 ¥ when the last remaining owner is destroyed, reassigned, or reset, the vector will be destroyed, and then also the stored Objects
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13) TDDD38 APiC++ Smartpointers 336
More about strong and weak pointers and circular references in C++
See:
http://visualstudiomagazine.com/articles/2012/10/19/circular-references.aspx
File: Standard-Smart-Pointers-OH-en © 2014 Tommy Olsson, IDA, Linköpings universitet (2014-11-13)