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).的更多相关文章

  1. C语言指针-从底层原理到花式技巧,用图文和代码帮你讲解透彻

    这是道哥的第014篇原创 目录 一.前言 二.变量与指针的本质 1. 内存地址 2. 32位与64位系统 3. 变量 4. 指针变量 5. 操作指针变量 5.1 指针变量自身的值 5.2 获取指针变量 ...

  2. Optaplanner规划引擎的工作原理及简单示例(2)

    开篇 在前面一篇关于规划引擎Optapalnner的文章里(Optaplanner规划引擎的工作原理及简单示例(1)),老农介绍了应用Optaplanner过程中需要掌握的一些基本概念,这些概念有且于 ...

  3. 深入理解指针—>指针函数与函数指针的区别

    一. 在学习过程中发现这"指针函数"与"函数指针"容易搞错,所以今天,我自己想一次把它搞清楚,找了一些资料,首先它们之间的定义: 1.指针函数是指带指针的函数, ...

  4. Spline样条函数 //C++关键字:operator // 重载函数 // 隐含的this指针 // 指针和const限定符

    在数学学科数值分析中,样条是一种特殊的函数,由多项式分段定义.样条插值是使用一种名为样条的特殊分段多项式进行插值的形式.由于样条插值可以使用低阶多项式样条实现较小的差值误差,这样就避免了使用高阶多项式 ...

  5. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...

  6. C语言指针系列 - 一级指针.一维数组,二级指针,二维数组,指针数组,数组指针,函数指针,指针函数

    1. 数组名 C语言中的数组名是一个特殊的存在, 从本质上来讲, 数组名是一个地址, 我们可以打印一个指针的值,和打印一个数组的值来观察出这个本质: int nArray[10] ={ 0 }; in ...

  7. C_C++指针指针应用详解

    前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其 ...

  8. HBase笔记:对HBase原理的简单理解

    早些时候学习hadoop的技术,我一直对里面两项技术倍感困惑,一个是zookeeper,一个就是Hbase了.现在有机会专职做大数据相关的项目,终于看到了HBase实战的项目,也因此有机会搞懂Hbas ...

  9. 编译原理(简单自动词法分析器LEX)

    编译原理(简单自动词法分析器LEX)源程序下载地址:  http://files.cnblogs.com/files/hujunzheng/%E6%B1%87%E7%BC%96%E5%8E%9F%E7 ...

随机推荐

  1. Spring整合Quartz定时任务 在集群、分布式系统中的应用(Mysql数据库环境)

    Spring整合Quartz定时任务 在集群.分布式系统中的应用(Mysql数据库环境)   转载:http://www.cnblogs.com/jiafuwei/p/6145280.html 单个Q ...

  2. 集成maven和Spring boot的profile功能

    思路:maven支持profile功能,当使用maven profile打包时,可以打包指定目录和指定文件,且可以修改文件中的变量.spring boot也支持profile功能,只要在applica ...

  3. Your Prediction Gets As Good As Your Data

    Your Prediction Gets As Good As Your Data May 5, 2015 by Kazem In the past, we have seen software en ...

  4. python学习笔记5--json处理

    import json #json串就是字符串. d = { 'car':{'color':'red','price':100,'count':50}, 'bus':{'color':'red','p ...

  5. 如何用javascript获取和设置css3属性

    ==================获取======================== 我想到的第一个思路 var test = document.getElementById('test'); c ...

  6. [转载]在Windows下搭建Android开发环境

    http://jingyan.baidu.com/article/bea41d437a41b6b4c51be6c1.html 在Windows下搭建Android开发环境 | 浏览:30780 | 更 ...

  7. [QuickRoR]Ruby on Rails开发环境安装

    1.Setup Ruby on Rails2.Test Web App3.Create the First Web App 1.Setup Ruby on Rails1) Download rubyi ...

  8. python技巧 使用值来排序一个字典

    In [8]: a={'x':11,'y':22,'c':4} In [9]: import operator In [10]: sorted(a.items(),key=operator.itemg ...

  9. 第8月第22天 python scrapy

    1. cd /Users/temp/Downloads/LagouSpider-master ls ls ls lagou/settings.py cat lagou/settings.py ls p ...

  10. Eric6启动时“无法定位序数4540于动态链接库LIBEAY32.dll”的错误

    参考自:https://blog.csdn.net/HongAndYi/article/details/80721478 在安装PyQt5的编程环境时,安装Eric6-17.12后运行eric6,却出 ...