C++智能指针,指针容器原理及简单实现(auto_ptr,scoped_ptr,ptr_vector).
C++智能指针,指针容器原理及简单实现(auto_ptr,scoped_ptr,ptr_vector).
前言
最近再写一个muduo的异步日志接触了很多智能指针,但是又不打算用boost库,只好模一个来用用了.
智能指针的本质即用栈上对象来管理堆上数据的生命周期.
智能指针本身是一个对象,它在栈上创建,构造的时候分配堆上资源,析构的时候释放资源,这样就避免了堆上数据资源泄露的情况.
同时重载它的-> 和 * 运算符实现如同裸指针一样的操作.
下面看看几个局部智能指针对象的实现代码。
auto_ptr
auto_ptr特点: 实现拷贝构造函数, 重载 = 运算符, 实现->、* 运算符, 使它能够像普通指针一样 使用,
同时通过release() 和 reset() 方法实现安全的转移使用权 .
#ifndef _AUTO_PTR_HH
#define _AUTO_PTR_HH
template<typename T>
class auto_ptr{
public:
explicit auto_ptr(T* p = 0):m_ptr(p){printf("1\n");
}
auto_ptr(auto_ptr& obj):m_ptr(obj.release()){printf("2\n");
}
auto_ptr& operator=(auto_ptr& obj){printf("3\n");
reset(obj.release());
return *this;
}
~auto_ptr(){printf("4\n");
delete m_ptr;
}
T* release(){
T* tmp = m_ptr;
m_ptr = 0;
return tmp;
}
void reset(T* p){
if(m_ptr != p)
delete m_ptr;
m_ptr = p;
}
T* get() const {
return m_ptr;
}
T* operator->(){
return get();
}
T& operator*(){
return *get();
}
private:
T* m_ptr;
};
#endif
测试代码:
#include "ScopePtr.hh"
#include "auto_ptr.hh"
#include <stdio.h>
class NonCopyable
{
protected: //构造函数可以被派生类调用,但不能直接构造对象
NonCopyable() {printf("Nocopy Constroctr\n");}
~NonCopyable() {printf("~Nocopy DeConstroctr\n");}
private:
NonCopyable(const NonCopyable &);
const NonCopyable &operator=(const NonCopyable &);
};
class Test// : private NonCopyable{
{public:
Test(){printf("Constroctr\n");}
~Test(){printf("~DeConstroctr\n");}
};
int main(){
//scoped_ptr<Test> st(new Test);
auto_ptr<Test> ap1(new Test);
auto_ptr<Test> ap2(new Test);
auto_ptr<Test> ap3(ap2);
ap2 = ap3;
getchar();
return 0;
}
Constroctr
1
Constroctr
1
2
3
4
4
~DeConstroctr
4
~DeConstroctr
scoped_ptr
这个是boost库里面的东西,它和auto_ptr正相反: 将拷贝构造和=重载 都配置为私有,已达到不允许转移拥有权的目的.
#ifndef _SCOPE_PTR_HH
#define _SCOPE_PTR_HH
// scoped_ptr mimics a built-in pointer except that it guarantees deletion
// of the object pointed to, either on destruction of the scoped_ptr or via
// an explicit reset(). scoped_ptr is a simple solution for simple needs;
// use shared_ptr or std::auto_ptr if your needs are more complex.
/*
scoped_ptr 是局部智能指针 不允许转让所有权。
*/
template <class T>
class scoped_ptr
{
public:
scoped_ptr(T *p = 0) :m_ptr(p) {
}
~scoped_ptr(){
delete m_ptr;
}
T&operator*() const {
return *m_ptr;
}
T*operator->() const {
return m_ptr;
}
void reset(T *p)//拥有权不允许转让 但是可以让智能指针指向另一个空间
{
if (p != m_ptr && m_ptr != 0)
delete m_ptr;
m_ptr = p;
}
T* get(){
return m_ptr;
}
private://将拷贝构造和赋值 以及判等判不等 都设置为私有方法
//对象不再能调用,即不能拷贝构造和赋值 也就达到了不让转移拥有权的目的
scoped_ptr(const scoped_ptr<T> &y);
scoped_ptr<T> operator=(const scoped_ptr<T> &);
void operator==(scoped_ptr<T> const &) const;
void operator!=(scoped_ptr<T> const &) const;
T* m_ptr;
};
#endif
ptr_vector
这个也是boost里面的东西,如果我们光放对象指针到vector里面,容器析构的时候虽然会析构自己开辟出来的存放指针的空间,但不会析构指针本身指向的空间,于是有了这个容器.
#ifndef _PTR_VECTOR_HH
#define _PTR_VECTOR_HH
#include "auto_ptr.hh"
#include <vector>
template<typename T>
class ptr_vector : public std::vector<T*>{
public:
~ptr_vector(){
clear();
}
void clear(){
typename std::vector<T*>::iterator it;
for(it = std::vector<T*>::begin(); it != std::vector<T*>::end(); ++it){
delete *it;//释放指针指向的内存.
}
/*
for(size_t i = 0; i < std::vector<T*>::size(); ++i){
delete std::vector<T*>::back();
}*/
std::vector<T*>::clear(); //释放指针本身.
}
typename std::vector<T*>::iterator erase(typename std::vector<T*>::iterator it){
if(it >= std::vector<T*>::begin() && it < std::vector<T*>::end()){
delete *it;
std::vector<T*>::erase(it);
}
}
void pop_back(){
if(std::vector<T*>::size() > 0){
delete std::vector<T*>::back();
std::vector<T*>::pop_back();
}
}
void push_back(T* const &v){
auto_ptr<T> ap(v);
std::vector<T*>::push_back(v);
ap.release();
}
void push_back(auto_ptr<T> &v){
std::vector<T*>::push_back(v.get());
v.release();
}
};
#endif
测试代码:
class Test// : private NonCopyable{
{public:
Test(int a = 99):a(a){printf("Constroctr\n");}
~Test(){printf("~DeConstroctr\n");}
int get(){return a;}
private:
int a;
};
int main(){
auto_ptr<Test> ap1(new Test(0));
auto_ptr<Test> ap2(new Test(1));
auto_ptr<Test> ap3(new Test(2));
printf("%d\n", ap1->get());
ptr_vector<Test> apv;
apv.push_back(ap1);
apv.push_back(ap2);
apv.push_back(ap3);
printf("%d %lu \n", apv.front()->get(),apv.size());
/*
apv.pop_back();
printf("%lu\n", apv.size());
apv.pop_back();
printf("%lu\n", apv.size());
apv.pop_back();
printf("%lu\n", apv.size());
*/
apv.pop_back();
printf("%lu\n", apv.size());
ptr_vector<Test>::iterator it = apv.begin();
apv.erase(it);
printf("%lu\n", apv.size());
getchar();
return 0;
}
Constroctr
Constroctr
Constroctr
0
0 3
~DeConstroctr
2
~DeConstroctr
1
~DeConstroctr
本文主介绍了智能指针的本质,及两种简单的智能指针实现与一个指针容器的实现.
事实上现在auto_ptr用的不多,如果没对原来传进来的指针进行处理,转移后,原来的指针为空了,如果有人去使用既会造成问题。
vector也存在很多问题,pop_back()一个空的容器,vector里面照样会做--size,这时候容器大小从0就变成了无限大,后果无法预料,.本例中对这种情况进行了处理. pop_back()一个空的vector将什么都不做. 但是vector用法还是有讲究的,不然容易造成问题.
C++智能指针,指针容器原理及简单实现(auto_ptr,scoped_ptr,ptr_vector).的更多相关文章
- C语言指针-从底层原理到花式技巧,用图文和代码帮你讲解透彻
这是道哥的第014篇原创 目录 一.前言 二.变量与指针的本质 1. 内存地址 2. 32位与64位系统 3. 变量 4. 指针变量 5. 操作指针变量 5.1 指针变量自身的值 5.2 获取指针变量 ...
- Optaplanner规划引擎的工作原理及简单示例(2)
开篇 在前面一篇关于规划引擎Optapalnner的文章里(Optaplanner规划引擎的工作原理及简单示例(1)),老农介绍了应用Optaplanner过程中需要掌握的一些基本概念,这些概念有且于 ...
- 深入理解指针—>指针函数与函数指针的区别
一. 在学习过程中发现这"指针函数"与"函数指针"容易搞错,所以今天,我自己想一次把它搞清楚,找了一些资料,首先它们之间的定义: 1.指针函数是指带指针的函数, ...
- Spline样条函数 //C++关键字:operator // 重载函数 // 隐含的this指针 // 指针和const限定符
在数学学科数值分析中,样条是一种特殊的函数,由多项式分段定义.样条插值是使用一种名为样条的特殊分段多项式进行插值的形式.由于样条插值可以使用低阶多项式样条实现较小的差值误差,这样就避免了使用高阶多项式 ...
- 转 Spring源码剖析——核心IOC容器原理
Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...
- C语言指针系列 - 一级指针.一维数组,二级指针,二维数组,指针数组,数组指针,函数指针,指针函数
1. 数组名 C语言中的数组名是一个特殊的存在, 从本质上来讲, 数组名是一个地址, 我们可以打印一个指针的值,和打印一个数组的值来观察出这个本质: int nArray[10] ={ 0 }; in ...
- C_C++指针指针应用详解
前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其 ...
- HBase笔记:对HBase原理的简单理解
早些时候学习hadoop的技术,我一直对里面两项技术倍感困惑,一个是zookeeper,一个就是Hbase了.现在有机会专职做大数据相关的项目,终于看到了HBase实战的项目,也因此有机会搞懂Hbas ...
- 编译原理(简单自动词法分析器LEX)
编译原理(简单自动词法分析器LEX)源程序下载地址: http://files.cnblogs.com/files/hujunzheng/%E6%B1%87%E7%BC%96%E5%8E%9F%E7 ...
随机推荐
- 关于xmlhttp会使用ie的缓存的问题及解决
在浏览器(如:IE)的客户端使用xmlhttp读取网络资源的时候,需要考虑到浏览器本地缓存的问题. 如果希望读取的数据是实时更新的,也就是不想从本地缓存中读取数据,我之前常用的方法是在请求网址后面加一 ...
- vue-devtools/安装vue-devtools
一.在github上下载压缩包,github下载地址:https://github.com/vuejs/vue-devtools 二.解压到本地的某盘 三.用你的npm中进入该文件夹下 在npm中执行 ...
- HDU 3389 阶梯博弈变形
n堆石子,每次选取两堆a!=b,(a+b)%2=1 && a!=b && 3|a+b,不能操作者输 选石子堆为奇数的等价于选取步数为奇数的,观察发现 1 3 4 是无法 ...
- 《翻译》PEP 380 – 委托子生成器语法
PEP 380 – 委托子生成器语法 翻译自: https://www.python.org/dev/peps/pep-0380/ 摘要 一项新的语法被提出了:生成器委托其部分操作给另一个生成器.委 ...
- 格式化 SQL 来提高效率
本文由 伯乐在线 - cucr 翻译,黄利民 校稿.未经许可,禁止转载!英文出处:msiman.ga.欢迎加入翻译小组. 背景 已格式化的SQL并不比未格式化SQL运行地更快.数据库可能真的不太在意你 ...
- Python 装饰器入门(下)
继续上次的进度:https://www.cnblogs.com/flashBoxer/p/9847521.html 正文: 装饰类 在类中有两种不通的方式使用装饰器,第一个和我们之前做过的函数非常相似 ...
- 记webpack下引入vue的方法(非.vue文件方式)
直接script引入下载静态的vue.js文件则最后用copy-webpack-plugin复制到一样的目录即可 使用npm安装的vue无法直接用 import vue from "vue& ...
- mysql_存储过程_后一行减去前一行
DELIMITER $$ /*统计单个用户登录次数的存过 @times_count int 返回值 @i 记录行号的变量 初始值为0 @temp 记录时间差的变量 @total 记录登录次数的变量 初 ...
- RESET MASTER和RESET SLAVE使用场景和说明【转】
[前言]在配置主从的时候经常会用到这两个语句,刚开始的时候还不清楚这两个语句的使用特性和使用场景. 经过测试整理了以下文档,希望能对大家有所帮助: [一]RESET MASTER参数 功能说明:删除所 ...
- 压缩跟踪Compressive Tracking(转)
这位博主总结的实在太好了,从原理到论文到代码,连论文都不用看:论文:http://blog.csdn.net/zouxy09/article/details/8118360 代码部分:http://b ...