In: Computer Science
I'm having trouble understanding smart pointer functions
what is get(), release(), reset(), swap() for unique pointers? How do I use it?
what is get(), reset(), swap(), unique(), use_count() for shared pointers? How do I use it?
what is expired(), lock(), reset(),swap(), use_count for weak pointer? How do I use it?
Smart Pointer Functions:
A smart pointer is a class that wraps a 'raw' (or 'bare') C++ pointer, to manage the lifetime of the object being pointed to. There is no single smart pointer type, but all of them try to abstract a raw pointer in a practical way.
If you feel you need to use pointers, you would normally want to use a smart pointer as this can alleviate many of the problems with raw pointers, mainly forgetting to delete the object and leaking memory.
With raw pointers, the programmer has to explicitly destroy the object when it is no longer useful.
Smart pointers have pointer semantics, not value semantics (well, not the way you mean it). Think of shared_ptr<T> as a T*; treat it as such (well, except for the reference counting and automatic deletion). Copying a smart pointer does not copy the object it points to, just like copying a T* does not copy the T it points to.
You can't copy a unique_ptr at all. The whole point of the class is that it cannot be copied; if it could, then it wouldn't be a unique (ie: singular) pointer to an object. You have to either pass it by some form of reference or by moving it.
Smart pointers are all about ownership of what they point to. Who owns this memory and who will be responsible for deleting it. unique_ptr represents unique ownership: exactly one piece of code owns this memory. You can transfer ownership (via move), but in so doing, you lose ownership of the memory. shared_ptr represents shared ownership.
A) Unique Pointers:
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope.
The following are it's pointer functions :
1) get() : Returns a pointer to the managed object or nullptr if no object is owned.
pointer get() const noexcept;
Parameters : none
Return value : Pointer to the managed object or nullptr if no object is owned.
Example
#include <iostream> #include <string> #include <memory> int main(){ std::unique_ptr<std::string> s_p(new std::string("Hello, world!")); std::string *s = s_p.get(); std::cout << *s << '\n'; }
Output:
Hello, world!
2) release() : Releases ownership of its stored pointer, by returning its value and replacing it with a null pointer.
pointer release() noexcept;
Parameters : none
Return value : A pointer to the object managed by unique_ptr before the call.
Example:
#include <iostream> #include <memory> int main () { std::unique_ptr<int> auto_pointer (new int); int * manual_pointer; *auto_pointer=10; manual_pointer = auto_pointer.release(); // (auto_pointer is now empty) std::cout << "manual_pointer points to " << *manual_pointer << '\n'; delete manual_pointer; return 0; }
Output:
manual_pointer points to 10
3) reset() : Destroys the object currently managed by the unique_ptr (if any) and takes ownership of p.
void reset (pointer p = pointer()) noexcept;
Parameters : Pointer whose ownership is taken over by the object.
Return value : none
Example :
#include <iostream> #include <memory> int main () { std::unique_ptr<int> up; // empty up.reset (new int); // takes ownership of pointer *up=5; std::cout << *up << '\n'; up.reset (new int); // deletes managed object, acquires new pointer *up=10; std::cout << *up << '\n'; up.reset(); // deletes managed object return 0; }
Output:
5 10
4) swap() : Exchanges the contents of the unique_ptr object with those of x, transferring ownership of any managed object between them without destroying either.
void swap (unique_ptr& x) noexcept;
Parameters : Another unique_ptr object of the same type (i.e., with the same class template parameters).
Return value : none
Example:
#include <iostream> #include <memory> int main () { std::unique_ptr<int> foo (new int(10)); std::unique_ptr<int> bar (new int(20)); foo.swap(bar); std::cout << "foo: " << *foo << '\n'; std::cout << "bar: " << *bar << '\n'; return 0; }
Output:
foo: 20 bar: 10
B) Shared Pointers
:std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object.
The following are it's pointer functions :
1) get() ; Returns the stored pointer.
element_type* get() const noexcept
Parameters : none
Return value : The stored pointer.
Example :
#include <iostream> #include <memory> #include <string_view> void output(std::string_view msg, int const* pInt){ std::cout << msg << *pInt << "\n"; } int main(){ int* pInt = new int(42); std::shared_ptr<int> pShared = std::make_shared<int>(42); output("Naked pointer ", pInt); // output("Shared pointer ", pShared); // compiler error output("Shared pointer with get() ", pShared.get()); delete pInt; }
Output:
Naked pointer 42 Shared pointer with get() 42
2) reset() : For signature (1) the object becomes empty (as if default-constructed).
void reset() noexcept;
Parameters : Pointer whose ownership is taken over by the object
Return Value : None
Example:
#include <iostream> #include <memory> int main () { std::shared_ptr<int> sp; // empty sp.reset (new int); // takes ownership of pointer *sp=10; std::cout << *sp << '\n'; sp.reset (new int); // deletes managed object, acquires new pointer *sp=20; std::cout << *sp << '\n'; sp.reset(); // deletes managed object return 0; }
Output:
10 20
3) swap() : Exchanges the contents of the shared_ptr object with those of x, transferring ownership of any managed object between them without destroying or altering the use count of either.
void swap (shared_ptr& x) noexcept;
Parameters : Another shared_ptr object of the same type (i.e., with the same class template parameter T).
Return Value : None
Example:
#include <iostream> #include <memory> int main () { std::shared_ptr<int> foo (new int(10)); std::shared_ptr<int> bar (new int(20)); foo.swap(bar); std::cout << "*foo: " << *foo << '\n'; std::cout << "*bar: " << *bar << '\n'; return 0; }
Output::
*foo: 20 *bar: 10
4) unique() : Returns whether the shared_ptr object does not share ownership over its pointer with other shared_ptr objects (i.e., it is unique).
bool unique() const noexcept;
Parameters : None
Return Value : true if this is a unique shared_ptr, false otherwise
Example :
#include <iostream> #include <memory> int main () { std::shared_ptr<int> foo; std::shared_ptr<int> bar (new int); std::cout << "foo unique?\n" << std::boolalpha; std::cout << "1: " << foo.unique() << '\n'; // false (empty) foo = bar; std::cout << "2: " << foo.unique() << '\n'; // false (shared with bar) bar = nullptr; std::cout << "3: " << foo.unique() << '\n'; // true return 0; }
Output :
foo unique? 1: false 2: false 3: true
5) use_count() : Returns the number of different shared_ptr instances (this included) managing the current object. If there is no managed object, 0 is returned.
long use_count() const noexcept;
Parameters : None
Return Value : the number of shared_ptr instances managing the current object or 0 if there is no managed object.
Example :
#include <memory> #include <iostream> void fun(std::shared_ptr<int> sp){ std::cout << "fun: sp.use_count() == " << sp.use_count() << '\n'; } int main() { auto sp1 = std::make_shared<int>(5); std::cout << "sp1.use_count() == " << sp1.use_count() << '\n'; fun(sp1); }
Output :
sp1.use_count() == 1 fun: sp.use_count() == 2
C) Weak Pointers :
std::weak_ptr 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, std::weak_ptr
is used to track the object, and it is converted to std::shared_ptr
to assume temporary ownership.
If the original std::shared_ptr is destroyed at this time, the object's lifetime is extended until the temporary std::shared_ptr is destroyed as well.std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It must be converted to std::shared_ptr in order to access the referenced object.
The following are its pointer functions:
1) expired() : Equivalent to use_count() == 0. The destructor for the managed object may not yet have been called, but this object's destruction is imminent (or may have already happened).
bool expired() const noexcept;
Parameters : None
Return Value : true if the managed object has already been deleted, false otherwise.
Example :
#include <iostream> #include <memory> std::weak_ptr<int> gw; void f(){ if (!gw.expired()) { std::cout << "gw is valid\n"; } else { std::cout << "gw is expired\n"; } } int main(){ { auto sp = std::make_shared<int>(42); gw = sp; f(); } f(); }
Output:
gw is valid gw is expired
2) lock() : Creates a new std::shared_ptr that shares ownership of the managed object. If there is no managed object, i.e. *this is empty, then the returned shared_ptr also is empty.
std::shared_ptr<T> lock() const noexcept;
Parameters : None
Return Value : A shared_ptr which shares ownership of the owned object if std::weak_ptr::expired returns false. Else returns default-constructed shared_ptr of type T.
Example :
#include <iostream> #include <memory> void observe(std::weak_ptr<int> weak) { if (auto observe = weak.lock()) { std::cout << "\tobserve() able to lock weak_ptr<>, value=" << *observe << "\n"; } else { std::cout << "\tobserve() unable to lock weak_ptr<>\n"; } } int main(){ std::weak_ptr<int> weak; std::cout << "weak_ptr<> not yet initialized\n"; observe(weak);{ auto shared = std::make_shared<int>(42); weak = shared; std::cout << "weak_ptr<> initialized with shared_ptr.\n"; observe(weak); } std::cout << "shared_ptr<> has been destructed due to scope exit.\n"; observe(weak); }
Output :
weak_ptr<> not yet initialized observe() unable to lock weak_ptr<> weak_ptr<> initialized with shared_ptr. observe() able to lock weak_ptr<>, value=42 shared_ptr<> has been destructed due to scope exit. observe() unable to lock weak_ptr<>
3) reset() : Releases the reference to the managed object. After the call *this manages no object.
The object becomes empty, as if default constructed.
void reset() noexcept;
Parameters : None
Return Value : None
Example :
#include <iostream> #include <memory> int main () { std::shared_ptr<int> sp (new int(10)); std::weak_ptr<int> wp(sp); std::cout << "1. wp " << (wp.expired()?"is":"is not") << " expired\n"; wp.reset(); std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired\n"; return 0; }
Output :
1. wp is not expired 2. wp is expired
4) swap() : Exchanges the contents of the weak_ptr object with those of x, swapping their owning groups and any stored data
void swap (weak_ptr& x) noexcept;
Parameters : Another weak_ptr object of the same type (i.e., with the same class template parameter T).
Return Value : None
Example :
#include <iostream> #include <memory> int main () { std::shared_ptr<int> sp1 (new int(10)); std::shared_ptr<int> sp2 (new int(20)); std::weak_ptr<int> wp1(sp1); std::weak_ptr<int> wp2(sp2); wp1.swap(wp2); std::cout << "sp1 -> " << *sp1 << '\n'; std::cout << "sp2 -> " << *sp2 << '\n'; std::cout << "wp1 -> " << *wp1.lock() << '\n'; std::cout << "wp2 -> " << *wp2.lock() << '\n'; return 0; }
Output :
sp1 -> 10 sp2 -> 20 wp1 -> 20 wp2 -> 10
5) use_count() : Returns the number of shared_ptr instances that share ownership of the managed object, or 0 if the managed object has already been deleted, i.e. *this is empty.
long use_count() const noexcept;
Parameters : None
Return Value : The number of shared_ptr instances sharing the ownership of the managed object at the instant of the call.
//* I Really Hope this helps you Understand :) *//