C++智能指针,指针容器原理及简单实现(auto_ptr,scoped_ptr,ptr_vector).
程序员文章站
2023-09-09 18:37:51
C++智能指针,指针容器原理及简单实现(auto_ptr,scoped_ptr,ptr_vector). [TOC] 前言 最近再写一个muduo的异步日志接触了很多智能指针,但是又不打算用boost库,只好模一个来用用了. 智能指针本身是一个对象,它在栈上创建,构造的时候分配堆上资源,析构的时候释 ......
目录
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用法还是有讲究的,不然容易造成问题.
下一篇: php实现的仿阿里巴巴实现同类产品翻页