目录
- 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 用法还是有讲究的, 不然容易造成问题.
来源: https://www.cnblogs.com/ailumiyana/p/9451761.html