智能指针的设计初衷是:
     C++中没有提供自己主动回收内存的机制,每次new对象之后都须要手动delete。稍不注意就memory leak。

智能指针能够解决上面遇到的问题。

C++中常见的智能指针包含(共七种):
     std::auto_ptr
     boost::scoped_ptr
     boost::shared_ptr
     boost::intrusive_ptr
     boost::scoped_array
     boost::shared_array
     boost::weak_ptr
    事实上,智能指针并非指针,它不过一个栈对象而已。
在栈对象的生命周期结束时,智能指针调用析构函数释放其管理的堆内存。
全部的智能指针都重载了'operator->'操作符,用来返回其管理对象的引用。从而能够
运行所管理对象的一些操作。


两个方法:
     - get()
          訪问智能指针包括的裸指针引用
     - reset()
          若传递參数为空或NULL 则智能指针会释放当前管理的内存。

          若传递參数为一个对象 则智能指针会释放当前管理的内存,管理新传入的对象。

假定有以下这个ManagedObj类。
class ManagedObj
{
public:
ManagedObj(int val = 0):m_val(val)
{
cout<<"Obj : "<<m_val<<endl;
} ~ManagedObj()
{
cout<<"~Obj : "<<m_val<<endl;
} void testFun()
{
cout<<"testFun : "<<m_info<<endl;
} public:
string m_info;
int m_val;
};

-> std::auto_ptr

属于STL
在namespace std中
加入头文件 #include <memory>就可以使用。
auto_ptr一般用于管理单个堆内存对象。

看以下这个样例:
// std::auto_ptr
void testAutoPtr1()
{
auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize")); if (atPtr.get()) // 推断智能指针是否为空
{
atPtr->testFun(); atPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
atPtr->testFun(); (*atPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
(*atPtr).testFun();
}
}
执行结果为:

OK 好像没什么问题。

我们接着測试:
void testAutoPtr2()
{
auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize")); if (atPtr.get()) // 推断智能指针是否为空
{
auto_ptr<ManagedObj> atPtr2; atPtr2 = atPtr; // 原因在这行代码
atPtr2->testFun();
atPtr->testFun(); // 崩溃在这行代码
}
}
执行结果为:

调试发现 最后一行代码出bug了。
为什么呢?
事实上是atPtr2剥夺了atPtr的内存管理全部权,导致atPtr悬空。

继续測试。

void testAutoPtr3()
{
auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize")); if (atPtr.get()) // 推断智能指针是否为空
{
atPtr.release();
}
}
执行结果为:

好像又出bug了。
我们并没有看到析构函数被调用的迹象,内存泄漏了。。
(逗我呢 怎么这么多bug?

)


别着急 第三个測试函数正确的写法应该是这种。
void testAutoPtr3()
{
auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize")); if (atPtr.get()) // 推断智能指针是否为空
{
//ManagedObj* temp = atPtr.release();
//delete temp; // 或者
atPtr.reset();
}
}

这才是我们想要看到的结果。


所以我们也发现。auto_ptr的release()函数仅仅是让出内存的管理权,并没有真正的释放内存。

总结:
     auto_ptr一般用于管理单个堆内存对象。

可是须要注意:

     a. 切记使用 "operator="。万一真用了,就不要再使用旧的对象了。

     b. release()方法不会释放内存 只不过让出全部权。

上面的auto_ptr使用起来确实不是非常方便,并且我们还有注意避开它的使用缺陷。

因此就出现了boost中的一些智能指针,以下一一介绍。

-> boost::scoped_ptr


属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。


关于boost库的安装教程 可參考:

与auto_ptr类似。scoped_ptr也可管理单个堆内存的对象,
可是它独享全部权,因此也就避免了auto_ptr的缺陷

OK。上代码測试。

// boost::scoped_ptr
void testScopedPtr()
{
boost::scoped_ptr<ManagedObj> scPtr(new ManagedObj(1, " initialize")); if (scPtr.get())
{
scPtr->testFun(); scPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
scPtr->testFun(); (*scPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
(*scPtr).testFun(); //scPtr.release(); // error scoped_ptr 没有成员release //boost::scoped_ptr<ManagedObj> scPtr2;
//scPtr2 = scPtr; // error scoped_ptr<T>::operator=(const scoped_ptr<ManagedObj> &)不可訪问
}
}
执行结果为:

注意凝视部分的代码。
scoped_ptr没有release()函数  屏蔽了operator=操作,
因此不会出现auto_ptr中出现的内存泄漏和崩溃问题。
但这也带来了还有一个新问题。我们无法复制智能指针。

因此出现了接下来的shared_ptr。

-> boost::shared_ptr

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。


因为scoped_ptr不同意赋值 拷贝 独享内存的全部权。
这里的shared_ptr是专门解决智能指针的内存全部权共享这个问题的。
其内部使用了引用计数。
来,測试吧。

// boost::shared_ptr
void testSharedPtr(boost::shared_ptr<ManagedObj> ptr)
{
ptr->testFun();
cout<<"shared_ptr use_count: "<<ptr.use_count()<<endl;
} void testSharedPtr1()
{
boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, " initialize")); if (shPtr.get())
{
shPtr->testFun(); shPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
shPtr->testFun(); (*shPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
(*shPtr).testFun();
} cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
testSharedPtr(shPtr);
cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
//shPtr.release(); // error shared_ptr 没有成员release
}
执行结果为:

能够看到。调用testSharedPtr()函数运行了一次复制操作,智能指针内部的引用计数+1。
在该函数调用结束后,引用计数自己主动-1。
上面介绍的几种智能指针都针对单个对象的内存管理。

事实上智能指针也可管理数组,接下来介绍boost::scoped_array和boost::shared_array。


-> boost::scoped_array

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。

boost::scoped_array用于管理动态数组。也是独享全部权的。


上代码:
// boost::scoped_array
void testScopedArray()
{
boost::scoped_array<ManagedObj> scArr(new ManagedObj[2]); // 动态数组初始化 if (scArr.get())
{
scArr[0].testFun(); scArr.get()[0].m_info += " [0] 1st append";
scArr[0].testFun(); //(*scArr)[0].m_info += " 2st append"; // error scoped_array没有重载operator*
//(*scArr)[0].testFun(); //scArr[0].release(); // error scoped_array 没有成员release boost::scoped_array<ManagedObj> scArr2;
//scArr2 = scArr; // error operator=不可訪问 屏蔽了operator= 禁止拷贝
}
}
执行结果为:

boost::scoped_array的使用和boost::scoped_ptr大致几乎相同。
都禁止拷贝 独享全部权。

注意:
     boost::scoped_array没有重载operator*操作符

-> boost::shared_array

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。


内部使用了引用计数,解决參数传递和拷贝赋值时的问题。


以下给出代码測试:
// boost::shared_array
void testSharedArray(boost::shared_array<ManagedObj> pArr)
{
cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
boost::shared_array<ManagedObj> pTempArr;
pTempArr = pArr;
cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
} void testSharedArray1()
{
boost::shared_array<ManagedObj> shArr(new ManagedObj[2]); if (shArr.get())
{
shArr[0].testFun(); shArr.get()[0].m_info += " [0] 1st append";
shArr[0].testFun();
shArr[1].testFun(); shArr.get()[0].m_info += " [1] 1st append";
shArr[1].testFun();
//(*shArr)[0].m_info += " [0] 2nd append"; // error 没有重载operator*操作符
} cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
testSharedArray(shArr);
cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
}
执行结果为:


-> boost::weak_ptr

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。

若我们只关心是否能使用对象。而不关心内部的引用计数。
boost::weak_ptr 是 boost::shared_ptr 的观察者(Observer)对象,
意味着boost::weak_ptr仅仅对boost::shared_ptr引用。可是并不更新
其引用计数。被观察的shared_ptr失效后,weak_ptr对应也失效。


上測试代码:
// boost::weak_ptr
void testWeakPtr()
{
boost::weak_ptr<ManagedObj> wPtr;
boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, "initialize")); cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
wPtr = shPtr;
cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
}
执行结果为:

我们发现赋值操作并没有更改引用计数。
boost::weak_ptr很多其它用于以下这样的场合:
     在基类中定义一个weak_ptr,用于观察其子类中的shared_ptr。这样基类仅仅要看自己的weak_ptr
是否为空就知道子类有没对自己赋值,而不影响子类中shared_ptr的引用计数。从而减少复杂度。更好管理对象。

-> boost::intrusive_ptr

属于boost库
在namespace boost中
加入头文件 #include<boost/smart_ptr.hpp> 就可以使用。

intrusive_ptr是一种插入式智能指针,其内部没有引用计数,
须要自己增加引用计数,否则会编译错误。

OK 到这儿为止,七种智能指针基本上都大致介绍完了。

參考:

http://blog.csdn.net/xt_xiaotian/article/details/5714477

完整的代码在这里

#include <iostream>
#include <memory>
#include <string>
#include <boost/smart_ptr.hpp> // add header file // namespace
using namespace std;
using namespace boost; // heap obj class
class ManagedObj
{
public:
ManagedObj(int val = 0, string info = "")
:m_val(val), m_info(info)
{
cout<<"Obj : "<<m_val<<m_info<<endl;
} ~ManagedObj()
{
cout<<"~Obj : "<<m_val<<m_info<<endl;
} void testFun()
{
cout<<"testFun : "<<m_info<<endl;
} public:
string m_info;
int m_val;
}; // std::auto_ptr
void testAutoPtr1()
{
auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize")); if (atPtr.get()) // 推断智能指针是否为空
{
atPtr->testFun(); atPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
atPtr->testFun(); (*atPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
(*atPtr).testFun();
}
} void testAutoPtr2()
{
auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize")); if (atPtr.get()) // 推断智能指针是否为空
{
auto_ptr<ManagedObj> atPtr2; atPtr2 = atPtr;
atPtr2->testFun();
atPtr->testFun();
}
} void testAutoPtr3()
{
auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize")); if (atPtr.get()) // 推断智能指针是否为空
{
//ManagedObj* temp = atPtr.release();
//delete temp; // 或者
atPtr.reset();
}
} // boost::scoped_ptr
void testScopedPtr()
{
boost::scoped_ptr<ManagedObj> scPtr(new ManagedObj(1, " initialize")); if (scPtr.get())
{
scPtr->testFun(); scPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
scPtr->testFun(); (*scPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
(*scPtr).testFun(); //scPtr.release(); // error scoped_ptr 没有成员release //boost::scoped_ptr<ManagedObj> scPtr2;
//scPtr2 = scPtr; // error scoped_ptr<T>::operator=(const scoped_ptr<ManagedObj> &)不可訪问
}
} // boost::shared_ptr
void testSharedPtr(boost::shared_ptr<ManagedObj> ptr)
{
ptr->testFun();
cout<<"shared_ptr use_count: "<<ptr.use_count()<<endl;
} void testSharedPtr1()
{
boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, " initialize")); if (shPtr.get())
{
shPtr->testFun(); shPtr.get()->m_info += " 1st append"; // get() 返回裸指针的引用
shPtr->testFun(); (*shPtr).m_info += " 2nd append"; // operator* 返回智能指针管理的对象
(*shPtr).testFun();
} cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
testSharedPtr(shPtr);
cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl; //shPtr.release(); // error shared_ptr 没有成员release
} // boost::scoped_array
void testScopedArray()
{
boost::scoped_array<ManagedObj> scArr(new ManagedObj[2]); // 动态数组初始化 if (scArr.get())
{
scArr[0].testFun(); scArr.get()[0].m_info += " [0] 1st append";
scArr[0].testFun(); //(*scArr)[0].m_info += " 2st append"; // error scoped_array没有重载operator*
//(*scArr)[0].testFun(); //scArr[0].release(); // error scoped_array 没有成员release boost::scoped_array<ManagedObj> scArr2;
//scArr2 = scArr; // error operator=不可訪问 屏蔽了operator= 禁止拷贝
}
} // boost::shared_array
void testSharedArray(boost::shared_array<ManagedObj> pArr)
{
cout<<"shared_arr use_count: "<<pArr.use_count()<<endl; boost::shared_array<ManagedObj> pTempArr;
pTempArr = pArr;
cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
} void testSharedArray1()
{
boost::shared_array<ManagedObj> shArr(new ManagedObj[2]); if (shArr.get())
{
shArr[0].testFun(); shArr.get()[0].m_info += " [0] 1st append";
shArr[0].testFun();
shArr[1].testFun(); shArr.get()[1].m_info += " [1] 1st append";
shArr[1].testFun();
//(*shArr)[0].m_info += " [0] 2nd append"; // error 没有重载operator*操作符
} cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
testSharedArray(shArr);
cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
} // boost::weak_ptr
void testWeakPtr()
{
boost::weak_ptr<ManagedObj> wPtr;
boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, "initialize")); cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
wPtr = shPtr;
cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
} // boost::intrusive_ptr
void testIntrusivePtr()
{
//boost::intrusive_ptr<ManagedObj> intPtr(new ManagedObj[1], false); // error 要自己加入引用计数
} // main function
int main(void)
{
// -----std::auto_ptr-----
//testAutoPtr();
//testAutoPtr2();
//testAutoPtr3(); // -----boost::scoped_ptr-----
//testScopedPtr(); // -----boost::shared_ptr-----
//testSharedPtr1(); // -----boost::scoped_array-----
//testScopedArray(); // -----boost::shared_array-----
//testSharedArray1(); // -----boost::weak_ptr-----
testWeakPtr(); return 0;
}

你说你会C++? —— 智能指针的更多相关文章

  1. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  2. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  3. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  4. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  5. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  6. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

  7. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  8. C++ 引用计数技术及智能指针的简单实现

    一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...

  9. C++11智能指针读书笔记;

    智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...

  10. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

随机推荐

  1. SqlDatasource简单用法

    http://blog.csdn.net/zxf1by1/article/details/7055015 增删改查和前台页面(拖拽过来的,但是包含参数的)

  2. centos7 docker镜像源设置

    由于docker他的镜像下载地址是国外官网源需要修改 添加 Docker 加速镜像(阿里云专属) 安装/升级你的Docker客户端 推荐安装1.10.0以上版本的Docker客户端,参考文档 dock ...

  3. 今日SGU 5.4

    SGU 127 题意:给你n个数字,和m,k,问你有多少个数字的m次幂可以被k整除 收获:快速幂 #include<bits/stdc++.h> #define de(x) cout< ...

  4. 重构insert update 比较两个datatbale

    #region 下载时重构insert(数据带null处理) public void DownDataInsert(DataTable _dt, string TableName,DBHelper d ...

  5. Android开发经验之在图片上随意点击移动文字

    只要在图片范围之内,文字可随意点击移动. package xiaosi.GetTextImage; import android.content.Context; import android.con ...

  6. POJ 1874 畅通工程续(最短路模板题)

    畅通工程续 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  7. Spring源码分析专题 —— 阅读指引

    阅读源码的意义 更深入理解框架原理,印象更深刻 学习优秀的编程风格.编程技巧.设计思想 解决实际问题,如修复框架中的bug,或是参考框架源码,结合实际业务需求编写一个独有的框架 阅读源码的方法 首先是 ...

  8. ArcGIS 10 影像、栅格数据格式批量转换

    转自原文 ArcGIS 10 影像.栅格数据格式批量转换 在做三维场景的时候,经常会涉及多种不同格式DEM数据或者影像的转换,如ASCII.GRID.IMG.TIFF等等,遇到大数据量时,我们就需要批 ...

  9. arukas 的 Endpoint

    arukas 的 Endpoint 什么是端点 What is Endpoint arukas.io 的实例几乎每周都自动重新启动,当实例重新启动时,其端口会更改.IP地址和端口的平均寿命是一周,有时 ...

  10. C Tricks(十八)—— 整数绝对值的实现

    为正还是为负:(对 int 类型而言,第一位为符号位,其余为数值,则右移 31 位,再与 1 求与) 如果为正 ⇒ 返回原值 如果为负 ⇒ 对其二进制形式各位取反 + 1 int abs(int x) ...