智能指针之 shared_ptr
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();
} void RefCountIncrease()
{
if (m_iRefCount != NULL)
{
++(*m_iRefCount);
}
} void RefCountDecrease()
{
if (m_iRefCount != NULL && --(*m_iRefCount) == )
{
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 ;
}
测试最后打印:
[yejy@yejy cmake-]$ ./smartptr
construct..
RefCount:
welcome Test..
welcome Test..
ptr is exit
destruct..
[yejy@yejy cmake-]$
shared_ptr主要需实现的功能点如下(以下总结引用自网络,非原创):
没有参数构造的时候,初始化为空,即对象和引用计数的两个指针都为0
使用指针为参数构造时,拥有此指针,在没有智能指针指向它时进行析构
智能指针复制时,两个智能指针共同拥有内部指针,引用计数同时+1
智能指针可以使用智能指针或普通指针重新赋值。重载=操作符,对于智能指针赋值,需要考虑是否自赋值,以避免将自身析构了后再重新赋值,而普通指针赋值给智能指针,则不需要考虑自赋值,因为两者本身是两个类型
获得底层指针的访问,定义
getPtrPointer()
和getPtrCounter()
来分别返回底层指针和引用计数,定义operator bool()
来处理智能指针隐式转换为bool
的情况重载
->
和×
操作符 ,来实现与普通指针相同的指针访问需要支持隐式指针类型转换,
static_cast
不支持而dynamic_cast
支持的转换则使用Cast<T2>()
成员函数来解决。考虑定义友元类,以防止指向派生类的智能指针有权限访问基类的内部对象;当转型不成功时,返回为空 (未实现)如果一个裸指针直接用来创建两个智能指针的话,期望的情况是当两个智能指针析构掉的时候,该指针会被delete两次从而崩溃(这是
shared_ptr
的特点)不处理循环引用(也是
shared_ptr
的特点),可以通过与weak_ptr
协作来打破循环实现
deleter
机制
最新文章
- 【转载】在IT界取得成功应该知道的10件事
- sublime插件 cssComb实现css自动排序及格式化
- 【CTO讲堂】以API为核心的移动应用云大发展时代
- Servlet作业--实现注册和登录
- sgu 102 Coprimes
- 杂题 UVAoj 107 The Cat in the Hat
- openStack images
- 一、ThinkPHP的介绍
- java_web学习(2)Servlet
- java读取txt文件内容
- centos虚拟机初始化脚本
- B. Secret Combination
- Leetcode_238_Product of Array Except Self
- JS中encodeURI()、decodeURI()、encodeURIComponent()和decodeURIComponent()编码与解码
- flex布局大讲解
- Python3+PyCharm+Django+Django REST framework开发教程
- jquery ajax的load()方法和load()事件
- [剑指Offer]6-从尾到头打印链表
- HDU4662(SummerTrainingDay03-B)
- go语言笔记(一)
热门文章
- python字典作为统计记录工具
- Cocos2D v2.0至v3.x简洁转换指南(一)
- android开发之http协议
- 网站开发进阶(二十二)HTML UI知识汇总(更新中...)
- 【Visual C++】游戏编程学习笔记之五:单一背景滚动
- 股票K线图
- The type java.lang.Object cannot be resolved. It is indirectly referenced from required .class files
- Invalid Subledger (XLA) Packages In Release 12.1.3
- Android群英传笔记——第一章:Android体系与系统架构
- android 自定义相机