
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 <memory> – raw pointers are basically weak, but not true weak, since they don’t know when the referenced object becomes unreachable • shared_ptr (strong) – reference counting smart pointer – the controlled resource is released when the use count (reference count) becomes 0 (unreachable) – supports copy semantics – shared_ptrs may be stored in containers • weak_ptr (weak) – are like raw pointers, but know when they dangle (have expired) • unique_ptr (strong) – supports moving instead of copying 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 <class T, class D = default_delete<T>> class unique_ptr { … }; {//some block unique_ptr<Object> up1{ new Object }; // single object version unique_ptr<Object[]> up2{ new Object[10] }; // array version unique_ptr<Object> up3{ up1 }; // error – copy constructor is removed up1 = up3; // error – copy assignment is removed unique_ptr<Object> up4{ std::move(up1) }; // ownership is transferred to up4 up1 = std::move(up4); // ownership is transferred to up1 } • 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<T> up1; // default constructor – up1 owns nothing unique_ptr<T> up2{ nullptr }; // up2 owns nothing unique_ptr<T> up3{ new T }; // taking a pointer to an object – up3 owns the pointed to object unique_ptr<T> up4{ std::move(up3) }; // move constructor – ownership is transferred to up4 unique_ptr<U> 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<Object>::deleter_type = get_deleter(); • 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 <typename T> struct default_delete { constexpr default_delete() noexcept = default; template <typename U> default_delete(const default_delete<U>&) noexcept; void operator()(T* ptr) const { static_assert(sizeof(T) > 0, "can’t delete pointer to incomplete type"); delete ptr; } }; • the array deleter is declared as an explicit specialization, which calls delete[] on the stored pointer template <typename T> struct default_delete<T[]> { constexpr default_delete() noexcept = default; void operator()(T* ptr) const { static_assert(sizeof(T) > 0, "can’t delete pointer to incomplete type"); delete[] ptr; } template <typename U> void operator()(U*) const = delete; }; 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<int> sp1{ new int{ 17 } }; // use count is set to 1 – provide a limited garbage-collection facility • shared_ptr objects can share ownership shared_ptr<int> sp2{ sp1 }; // use count is increased to 2 – 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<int> sp3{ p }; // use count is set to 1 shared_ptr<int> sp4{ p }; // use count is set to 1 – 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<int> sp1; // default constructor – sp1 is empty, use count of zero shared_ptr<int> sp2{ nullptr }; // from null pointer – same as default construction shared_ptr<int> sp3{ new int{17} }; // from pointer – sp3 owns the pointer, use count is set to 1 shared_ptr<int> sp4{ sp3 }; // copy constructor – if sp3 is not empty ownership is shared shared_ptr<int> sp5{ std::move(sp3) }; // move constructor – sp3 becomes empty, as if default-constructed shared_ptr<int> sp6{ wp }; // copy from weak_ptr – bad_weak_ptr thrown if wp has expired shared_ptr<int> sp7{ up }; // move from unique_ptr, or auto_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<int>(17); // make_shared returns shared_ptr<int> (copy assignment) 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)
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages20 Page
-
File Size-