Header file < memory >
Characteristic:
(1) The main purpose of smart pointer is to facilitate the management of resources and automatically release resources without pointer reference.
(2) Use reference counts to identify whether there are any redundant pointers pointing to the resource. (Note that shart_ptr itself takes up one reference)
(3) In the assignment operation, the reference count of the original resource will be reduced by one, and the reference count of the new resource will be increased by one.
std::shared_ptr<Test> p1(new Test);
std::shared_ptr<Test> p2(new Test);
p1 = p2;
(4) Reference counting plus one/minus one operation is atomic, so thread-safe.
(5) std::shared_ptr is twice the size of the original pointer because it has an internal pointer to the resource and a pointer to the reference count.
(6) Reference counting is allocated dynamically, std::shared_ptr supports copy, and the number of reference counts before the new pointer can be obtained.
(7) When the last object is destructed, memory is really released.
Membership functions:
(1)use_count returns the number of reference counts.
(2) Whether unique return is exclusive ownership (use_count is 1).
(3)swap exchanges two shared_ptr objects (i.e. objects owned by swap).
(4)reset abandons the ownership of internal objects or changes in ownership objects, which will reduce the reference count of the original objects.
(5)get returns the internal object (pointer), because the method has been overloaded, so it is the same as using the object directly. For example, shared_ptr < int > sp (new int (1)); SP and sp.get() are equivalent.
The following code demonstrates the usage and characteristics of each function:
std::shared_ptr<int> sp0(new int(2)); std::shared_ptr<int> sp1(new int(11)); std::shared_ptr<int> sp2 = sp1; printf("%d\n", *sp0); // 2 printf("%d\n", *sp1); // 11 printf("%d\n", *sp2); // 11 sp1.swap(sp0); printf("%d\n", *sp0); // 11 printf("%d\n", *sp1); // 2 printf("%d\n", *sp2); // 11 std::shared_ptr<int> sp3(new int(22)); std::shared_ptr<int> sp4 = sp3; printf("%d\n", *sp3); // 22 printf("%d\n", *sp4); // 22 sp3.reset(); printf("%d\n", sp3.use_count()); // 0 printf("%d\n", sp4.use_count()); // 1 printf("%d\n", sp3); // 0 printf("%d\n", sp4); // Point to the address of the object you own std::shared_ptr<int> sp5(new int(22)); std::shared_ptr<int> sp6 = sp5; std::shared_ptr<int> sp7 = sp5; printf("%d\n", *sp5); // 22 printf("%d\n", *sp6); // 22 printf("%d\n", *sp7); // 22 printf("%d\n", sp5.use_count()); // 3 printf("%d\n", sp6.use_count()); // 3 printf("%d\n", sp7.use_count()); // 3 sp5.reset(new int(33)); printf("%d\n", sp5.use_count()); // 1 printf("%d\n", sp6.use_count()); // 2 printf("%d\n", sp7.use_count()); // 2 printf("%d\n", *sp5); // 33 printf("%d\n", *sp6); // 22 printf("%d\n", *sp7); // 22
On the mak_shared function:
The safest way to allocate and use dynamic memory is to call a standard library function named make_shared, which allocates an object in dynamic memory and initializes it to return the shared_ptr of the object. Like pointers only, make_shared is also defined in the header file memory.
#include <iostream> using namespace std; int main() { shared_ptr<int> p3 = make_shared<int>(42); cout<<*p3<<endl; shared_ptr<string> pstr = make_shared<string>("99999"); cout<<*pstr<<endl; shared_ptr<int> pint = make_shared<int>(); //Default initialization is 0 cout<<*pint<<endl; auto pau = make_shared<string>("auto"); //It's simpler and more common. cout<<*pau<<endl; }