std::shared_ptr 是通过指针保持对象共享所有权的智能指针. 多个 shared_ptr 对象可占有同一对象大概实现了一下, 主要实现原理为, 共享指针内部持有堆资源的指针以及引用计数的指针, 通过对这两个指针的维护, 达到多个共享对象对同一资源的控制
实现主要分为三个文件. share_ptr.h,smart_ptr_define.h, main.cpp (编译平台: Linux centos 7.0 编译器: gcc 4.8.5)
- //smart_ptr_define.h
- #ifndef __SMART_PTR_DEFINE_H__
- #define __SMART_PTR_DEFINE_H__
- #include <assert.h>
- #define PTR_ASSERT(x) assert(x)
- #define _SMART_PTR_BEGIN namespace smartptr {
- #define _SMART_PTR_END }
- #define _SMART_PTR ::smartptr::
- #endif
主要实现文件 share_ptr.h
- #ifndef __SHARE_PTR_H__
- #define __SHARE_PTR_H__
- #include <iostream>
- #include "smart_ptr_define.h"
- _SMART_PTR_BEGIN
- template <class T>
- struct default_deleter
- {
- void operator()(T* ptr)
- {
- if (ptr != NULL)
- {
- delete ptr;
- ptr = NULL;
- }
- }
- };
- template <class T, class deleter = default_deleter<T>>
- class shared_ptr
- {
- public:
- typedef shared_ptr<T, deleter> SHARE_PTR;
- shared_ptr()
- {
- m_ptr = NULL;
- m_iRefCount = NULL;
- }
- explicit shared_ptr(T* ptr)
- {
- if (ptr != NULL)
- {
- m_ptr = ptr;
- RefCountInit();
- }
- }
- shared_ptr(deleter d, T* ptr)
- {
- if (ptr != NULL)
- {
- m_ptr = ptr;
- m_deleter = d;
- RefCountInit();
- }
- }
- // 拷贝构造
- shared_ptr(const SHARE_PTR& sh_ptr)
- {
- if (sh_ptr.m_ptr != NULL)
- {
- m_ptr = sh_ptr.m_ptr;
- m_deleter = sh_ptr.m_deleter;
- m_iRefCount = sh_ptr.m_iRefCount;
- RefCountIncrease();
- }
- }
- // 赋值运算符
- SHARE_PTR& operator = (const SHARE_PTR& sh_ptr)
- {
- if (this != &sh_ptr)
- {
- RefCountDecrease();
- if (sh_ptr.m_ptr != NULL)
- {
- m_ptr = sh_ptr.m_ptr;
- m_deleter = sh_ptr.m_deleter;
- m_iRefCount = sh_ptr.m_iRefCount;
- RefCountIncrease();
- }
- }
- return (*this);
- }
- ~shared_ptr()
- {
- RefCountDecrease();
- }
- public:
- // 提领操作
- T& operator*()
- {
- PTR_ASSERT(m_ptr != NULL);
- return *(m_ptr);
- }
- // 原始指针操作
- T* operator->()
- {
- PTR_ASSERT(m_ptr != NULL);
- return m_ptr;
- }
- operator bool() const
- {
- return m_ptr != NULL;
- }
- // 取得原始指针
- T* getPointer()
- {
- PTR_ASSERT(m_ptr != NULL);
- return m_ptr;
- }
- // 获得引用计数
- int getRefCount()
- {
- PTR_ASSERT(m_iRefCount != NULL);
- return *m_iRefCount;
- }
- private:
- void RefCountInit()
- {
- m_iRefCount = new int(1);
- }
- void RefCountIncrease()
- {
- if (m_iRefCount != NULL)
- {
- ++(*m_iRefCount);
- }
- }
- void RefCountDecrease()
- {
- if (m_iRefCount != NULL && --(*m_iRefCount) == 0)
- {
- m_deleter(m_ptr);
- delete m_iRefCount;
- m_ptr = NULL;
- m_iRefCount = NULL;
- }
- }
- private:
- int* m_iRefCount; // 引用计数
- T* m_ptr; // 对象指针
- deleter m_deleter; // 删除器
- };
- _SMART_PTR_END
- #endif // !__SHARE_PTR_H__
main 函数测试
- #include "share_ptr.h"
- #include <memory>
- class Test
- {
- public:
- Test()
- {
- std::cout <<"construct.." << std::endl;
- }
- void method()
- {
- std::cout << "welcome Test.." << std::endl;
- }
- ~Test()
- {
- std::cout << "destruct.." << std::endl;
- }
- };
- int main()
- {
- Test* t1 = new Test();
- _SMART_PTR shared_ptr<Test> shptr(t1);
- _SMART_PTR shared_ptr<Test> shptr1(shptr);
- _SMART_PTR shared_ptr<Test> shptr2 = shptr1;
- std::cout <<"RefCount:" << shptr2.getRefCount() << std::endl;
- shptr2->method();
- (*shptr2).method();
- if (shptr2)
- {
- std::cout <<"ptr is exit" << std::endl;
- }
- return 0;
- }
测试最后打印:
[yejy@yejy cmake-00]$ ./smartptr
construct..
RefCount: 3
welcome Test..
welcome Test..
ptr is exit
destruct..
[yejy@yejy cmake-00]$
shared_ptr 主要需实现的功能点如下 (以下总结引用自网络, 非原创):
没有参数构造的时候, 初始化为空, 即对象和引用计数的两个指针都为 0
使用指针为参数构造时, 拥有此指针, 在没有智能指针指向它时进行析构
智能指针复制时, 两个智能指针共同拥有内部指针, 引用计数同时 + 1
智能指针可以使用智能指针或普通指针重新赋值. 重载 = 操作符, 对于智能指针赋值, 需要考虑是否自赋值, 以避免将自身析构了后再重新赋值, 而普通指针赋值给智能指针, 则不需要考虑自赋值, 因为两者本身是两个类型
获得底层指针的访问, 定义 getPtrPointer() 和 getPtrCounter() 来分别返回底层指针和引用计数, 定义 operator bool() 来处理智能指针隐式转换为 bool 的情况
重载 -> 和 × 操作符 , 来实现与普通指针相同的指针访问
需要支持隐式指针类型转换, static_cast 不支持而 dynamic_cast 支持的转换则使用 Cast<T2>() 成员函数来解决. 考虑定义友元类, 以防止指向派生类的智能指针有权限访问基类的内部对象; 当转型不成功时, 返回为空 (未实现)
如果一个裸指针直接用来创建两个智能指针的话, 期望的情况是当两个智能指针析构掉的时候, 该指针会被 delete 两次从而崩溃 (这是 shared_ptr 的特点)
不处理循环引用 (也是 shared_ptr 的特点), 可以通过与 weak_ptr 协作来打破循环
实现 deleter 机制
来源: https://www.cnblogs.com/blog-yejy/p/9030722.html