zoukankan      html  css  js  c++  java
  • 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
    ");
    	}
    	
    	auto_ptr(auto_ptr& obj):m_ptr(obj.release()){printf("2
    ");
    	}
    	
    	auto_ptr& operator=(auto_ptr& obj){printf("3
    ");
    		reset(obj.release());
    		return *this;
    	}
    	
    	~auto_ptr(){printf("4
    ");
    		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
    ");}
        ~NonCopyable() {printf("~Nocopy DeConstroctr
    ");}
    private:
        NonCopyable(const NonCopyable &);
        const NonCopyable &operator=(const NonCopyable &);
    };
    
    
    class Test// : private NonCopyable{
    {public:
    	Test(){printf("Constroctr
    ");}
    	~Test(){printf("~DeConstroctr
    ");}
    };
    
    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
    ");}
    	~Test(){printf("~DeConstroctr
    ");}
    	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
    ", ap1->get());
    	
    	ptr_vector<Test> apv;
    	apv.push_back(ap1);
    	apv.push_back(ap2);
    	apv.push_back(ap3);
    	printf("%d %lu 
    ", apv.front()->get(),apv.size());
    /*
    	apv.pop_back();
    	printf("%lu
    ", apv.size());
    
    	apv.pop_back();
    	printf("%lu
    ", apv.size());
    	
    	apv.pop_back();
    	printf("%lu
    ", apv.size());
    */
    	apv.pop_back();
    	printf("%lu
    ", apv.size());
    	
    	
    	ptr_vector<Test>::iterator it = apv.begin();
    	apv.erase(it);
    	printf("%lu
    ", 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用法还是有讲究的,不然容易造成问题.

  • 相关阅读:
    requests模块
    爬虫基础
    forms组件
    分页器组件
    cookie与session组件
    Auth模块
    中间件组件
    git
    Ajax
    《Java程序设计》实验二 实验报告
  • 原文地址:https://www.cnblogs.com/ailumiyana/p/9451761.html
Copyright © 2011-2022 走看看