目录

- #include
- #include
- #include
- #include
- #include
-
- struct Base
- {
- Base() { std::cout << " Base::Base()\n"; }
- // 注意:此处非虚析构函数 OK
- ~Base() { std::cout << " Base::~Base()\n"; }
- };
-
- struct Derived: public Base
- {
- Derived() { std::cout << " Derived::Derived()\n"; }
- ~Derived() { std::cout << " Derived::~Derived()\n"; }
- };
-
- void thr(std::shared_ptr
p) - {
- std::this_thread::sleep_for(std::chrono::seconds(1));
- std::shared_ptr
lp = p; // 线程安全,虽然自增共享的 use_count - {
- static std::mutex io_mutex;
- std::lock_guard
lk(io_mutex) ; - std::cout << "local pointer in a thread:\n"
- << " lp.get() = " << lp.get()
- << ", lp.use_count() = " << lp.use_count() << '\n';
- }
- }
-
- int main()
- {
- std::shared_ptr
p = std::make_shared(); -
- std::cout << "Created a shared Derived (as a pointer to Base)\n"
- << " p.get() = " << p.get()
- << ", p.use_count() = " << p.use_count() << '\n';
- std::thread t1(thr, p), t2(thr, p), t3(thr, p);
- p.reset(); // 从 main 释放所有权
- std::cout << "Shared ownership between 3 threads and released\n"
- << "ownership from main:\n"
- << " p.get() = " << p.get()
- << ", p.use_count() = " << p.use_count() << '\n';
- t1.join(); t2.join(); t3.join();
- std::cout << "All threads completed, the last one deleted Derived\n";
- }

shared_ptr是一个引用计数智能指针,用于共享对象的所有有权,也就是说可以多个指针指向一个对象
- class Object {
- private:
- int value;
- public:
- Object(int x = 0) :value(x) { cout << "Constructor Object ..." << endl; }
- ~Object() { cout << "Destroy Object ..." << endl; }
- int& Value() { return value; }
- const int& Value()const { return value; }
- };
-
- int main() {
- shared_ptr;
- cout << (*pObj).Value() << endl;
- cout << "pObj 引用计数:" << pObj.use_count() << endl;
- shared_ptr
- cout << "pObj 引用计数:" << pObj.use_count() << endl;
- cout << "pObj 引用计数:" << pObj2.use_count() << endl;
- return 0;
- }

从上面这段代码中,我们对shared_ptr指针有了一些直观的了解。
一方面,跟STL中大多数容器类型一样, shared_ptr 也是模板类,因此在创建shared. ptr时需要指定其指向的类型。另一方面,正如其名一样,shared_ptr 指针允许让多个该类型的指针共享同一堆分配对象。同时shared_ptr 使用经典的“引用计数"方法来管理对象资源,每个shared_ptr对象关联一个共享的引用计数。
对于shared_ ptr 在拷贝和赋值时的行为是,每个shared _ptr 都有一个关联的计数值, 通常称为引用计数。无论何时我们拷贝一个shared_ptr,计数器都会递增。
例如,当用一个shared_ptr 初始化另一个 shred_ptr,或将它当做参数传递给一个函数以及作为函数的返回值时,它所关联的计数器就会递增。
当我们给shared_ ptr 赋予一个新值或是shared ptr 被销毁(例如一个局部的shared_ ptr离开其作用域)时,计数器就会递减。shared_ ptr 对象的计数器变为0,它就会自动释放自己所管理的对象。
对比我们上面的代码可以看到:当我们将一个指向Object对象的指针交给pObj管理后,其关联的引用计数为1。接下来,我们用pObj初始化pObj2,两者关联的引用计数值增加为2。随后,函数结束, pObj 和PObj2相继离开函数作用域,相应的引用计数值分别自减1最后变为0,于是Object对象被自动释放(调用其析构函数)。
最安全和高效的方法是调用make_shared库函数,该函数会在堆中分配一个对象并初始化, 最后返回指向此对象的share_ptr实例。如果你不想使用make_shared,也可以先明确new出一个对象, 然后把其原始指针传递给share_ptr 的构造函数。
- int main() {
- shared_ptr
ptr = make_shared(10,'s'); - cout << *ptr << endl;
- int* p = new int(10);
- shared_ptr<int> pInt(p);
- cout << *pInt << endl;
- }
shared_ptr的使用方式与普通指针的使用方式类似,既可以使用解引用操作符*获得原始对象进而访问其各个成员,也可以使用指针访问符->来访问原始对象的各个成员。
我们可以用一个shared_ptr对象来初始化另一个share_ptr 实例,该操作会增加其引用计数值。
- int main() {
- shared_ptr
pStr = make_shared(10, 's'); - cout << pStr.use_count() << endl;
- shared_ptr
pStr2(pStr) ; - cout << pStr.use_count() << endl;
- cout << pStr2.use_count() << endl;
- }

如果sharedp_tr实例p和另一个shared_ptr 实例q所指向的类型相同或者可以相互转换,我们还可以进行诸如p =q这样赋值操作。该操作会递减p的引用计数值,递增q的引用计数值。
- class Object {
- private:
- string value;
- public:
- Object(string x = "") :value(x) { cout << value << "Create Object.." << endl; }
- ~Object() { cout << value << "Destroy Object.." << endl; }
- string& Value() { return value; }
- const string& Value() const { return value; }
-
- };
- int main() {
- shared_ptr
- shared_ptr
pObj1 = make_shared("b.text"); - cout << pObj.use_count() << endl;
- cout << pObj1.use_count() << endl;
- pObj = pObj1;
- cout << pObj.use_count()<< endl;
- cout << pObj1.use_count() << endl;
- return 0;
- }
shared_ptr提供两个检查共享引用计数值,分别是unique()和use_cout();
- #include
- template <class _Ty>
- class MyDeletor
- {
- public:
- MyDeletor() = default;
- void operator ()(_Ty* ptr)const
- {
- if (ptr != nullptr)
- {
- delete ptr;
- }
- }
- };
- template <class _Ty>
- class RefCnt
- {
- public:
- _Ty* mptr;
- std::atomic_int ref;
- public:
- RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr) {}
- ~RefCnt() {}
- };
- template<class _Ty,class _Dx=MyDeletor<_Ty>>
- class my_shared_ptr
- {
- private:
- RefCnt<_Ty>* ptr;
- _Dx mDeletor;
- public:
- my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr)
- {
- if (p != nullptr)
- {
- ptr = new RefCnt(p);
- }
- }
- my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr)
- {
- if (ptr != nullptr)
- {
- ptr->ref += 1;
- }
- }
- my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
- {
- _Y.ptr = nullptr;
- }
- operator bool()const { return ptr != nullptr; }
- my_shared_ptr& operator=(const my_shared_ptr& _Y)
- {
- if (this == &_Y || this->ptr == _Y.ptr)return this;
- if (ptr != nullptr && --ptr->ref == 0)
- {
- mDeletor(ptr);
- }
- ptr = _Y.ptr;
- if (ptr != nullptr)
- {
- ptr->ref += 1;
- }
- return *this;
- }
- my_shared_ptr& operator=(my_shared_ptr&& _Y)
- {
- if (this == &_Y)return this;
- if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr)
- {
- this->ptr->ref -= 1;
- _Y.ptr = nullptr;
- return *this;
- }
- if (this->ptr != nullptr && --ptr->ref == 0)
- {
- mDeletor(ptr);
- }
- ptr = _Y.ptr;
- _Y.ptr = nullptr;
- return *this;
- }
- void reset(_Ty* p = nullptr)
- {
- if (this->ptr != nullptr && --this->ptr->ref == 0)
- {
- mDeletor(ptr);
- }
- ptr = new RefCnt<_Ty>(p);
- }
- ~my_shared_ptr()
- {
- if (this->ptr != nullptr && --this->ptr->ref == 0)
- {
- mDeletor(ptr->mptr);
- delete ptr;
- }
- ptr = nullptr;
- }
- _Ty* get()const
- {
- return ptr->mptr;
- }
- _Ty& operator*()const
- {
- return *get();
- }
- _Ty* operator ->()const
- {
- return get();
- }
- size_t use_count()const
- {
- if (this->ptr == nullptr)return 0;
- return this->ptr->ref;
- }
- void swap(my_shared_ptr* r)
- {
- std::swap(this->ptr, r->ptr);
- }
- };
- template <class _Ty>
- class MyDeletor<_Ty[]>
- {
- public:
- MyDeletor() = default;
- void operator ()(_Ty* ptr)const
- {
- if (ptr != nullptr)
- {
- delete []ptr;
- }
- }
- };
- template <class _Ty>
- class RefCnt
- {
- public:
- _Ty* mptr;
- std::atomic_int ref;
- public:
- RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr) {}
- ~RefCnt() {}
- };
- template<class _Ty, class _Dx >
- class my_shared_ptr<_Ty[],_Dx>
- {
- private:
- RefCnt<_Ty>* ptr;
- _Dx mDeletor;
- public:
- my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr)
- {
- if (p != nullptr)
- {
- ptr = new RefCnt(p);
- }
- }
- my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr)
- {
- if (ptr != nullptr)
- {
- ptr->ref += 1;
- }
- }
- my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
- {
- _Y.ptr = nullptr;
- }
- operator bool()const { return ptr != nullptr; }
- my_shared_ptr& operator=(const my_shared_ptr& _Y)
- {
- if (this == &_Y || this->ptr == _Y.ptr)return this;
- if (ptr != nullptr && --ptr->ref == 0)
- {
- mDeletor(ptr);
- }
- ptr = _Y.ptr;
- if (ptr != nullptr)
- {
- ptr->ref += 1;
- }
- return *this;
- }
- my_shared_ptr& operator=(my_shared_ptr&& _Y)
- {
- if (this == &_Y)return this;
- if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr)
- {
- this->ptr->ref -= 1;
- _Y.ptr = nullptr;
- return *this;
- }
- if (this->ptr != nullptr && --ptr->ref == 0)
- {
- mDeletor(ptr);
- }
- ptr = _Y.ptr;
- _Y.ptr = nullptr;
- return *this;
- }
- void reset(_Ty* p = nullptr)
- {
- if (this->ptr != nullptr && --this->ptr->ref == 0)
- {
- mDeletor(ptr);
- }
- ptr = new RefCnt<_Ty>(p);
- }
- ~my_shared_ptr()
- {
- if (this->ptr != nullptr && --this->ptr->ref == 0)
- {
- mDeletor(ptr->mptr);
- delete ptr;
- }
- ptr = nullptr;
- }
- _Ty* get()const
- {
- return ptr->mptr;
- }
- _Ty& operator*()const
- {
- return *get();
- }
- _Ty* operator ->()const
- {
- return get();
- }
- size_t use_count()const
- {
- if (this->ptr == nullptr)return 0;
- return this->ptr->ref;
- }
- void swap(my_shared_ptr* r)
- {
- std::swap(this->ptr, r->ptr);
- }
- _Ty& operator[](const int idx)const
- {
- return ptr->mptr[idx];
- }
- };
具体分析一下为什么“因为shared_ptr有两个数据成员,读写操作不能原子化”使得多线程读写同一个shared_ptr 对象需要加锁。
shared_ptr 是引用计数型(reference counting)智能指针,几乎所有的实现都采用在堆(heap)上放个计数值(count)。
- class Object {
- private:
- int value;
- public:
- Object(int x=0):value(x){}
- ~Object() {}
- int& Value() { return value; }
- const int& Value() const { return value; }
- };
- int main() {
- shared_ptr
apa(new Object(10)) ; - shared_ptr
apb = apa; - return 0;
- }



shared_ptr 作为unordered_map的key如果把sharedp_tr放到unordered_set中,或者用于unordered_map 的key,那么要小心hash table 退化为链表。
但是其hash_value是shared_ptr隐式转换为bool的结果。也就是说,如果不自定义hash函数,那么
unordered_ {set/map} 会退化为链表。
为什么要尽量使用make_shared?(申请被管理对象以及引用计数的内存;调用适当的构造函数初始化对象;返回一个shared_ptr为了节省一次内存分配,原来shared_ptr