前言
C++ 标准模板库 STL(Standard Template Library) 一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,其中 auto_ptr 是 C++98 提出的,C++11 已将其摒弃,并提出了 unique_ptr 替代 auto_ptr。虽然 auto_ptr 已被摒弃,但在实际项目中仍可使用,但建议使用更加安全的 unique_ptr,后文会详细叙述。shared_ptr 和 weak_ptr 则是 C+11 从准标准库 Boost 中引入的两种智能指针。此外,Boost 库还提出了 boost::scoped_ptr、boost::scoped_array、boost::intrusive_ptr 等智能指针,虽然尚未得到 C++ 标准采纳,但是在开发实践中可以使用。
一 auto_ptr
auto_ptr 同样是 STL 智能指针家族的成员之一,由 C++98 引入,定义在头文件。其功能和用法类似于 unique_ptr,由 new expression 获得对象,在 auto_ptr 对象销毁时,他所管理的对象也会自动被 delete 掉。
下面是一些成员函数及其简介
- get:得到对象类管理的对象指针
- operator*:得到管理的对象
- operator->:等价于(*class).,用于获取对象的某个成员
- release:将管理对象的指针返回并设置类内指针为null
- operator= :相当于调用release之后将返回值构造为新的类初始化左边的类,Release and copy auto_ptr
- reset:若无参数直接释放当前对象否则用参数重新设置当前值,无返回值
下面是一个小例子
#include <iostream> #include <memory> int main() {
/* get:得到对象类管理的对象指针 operator*:得到管理的对象 operator->:等价于(*class).,用于获取对象的某个成员 release:将管理对象的指针返回并设置类内指针为null operator= :相当于调用release之后将返回值构造为新的类初始化左边的类,Release and copy auto_ptr reset:若无参数直接释放当前对象否则用参数重新设置当前值,无返回值 */ std::auto_ptr<int> a; a.reset(new int);//reset:当前对象否则用参数重新设置当前值,无返回值 *a = 1; cout << "a:" << *a << endl;// operator*:得到管理的对象 *a = 2; std::auto_ptr<int> b; b = a;//operator= :相当于调用release之后将返回值构造为新的类初始化左边的类, if (a.get())//get:得到对象类管理的对象指针 {
cout << "a:" << *a << endl; } cout << "b:" << *b << endl; *b = 3; int *c = b.release();//release:将管理对象的指针返回并设置类内指针为null if (a.get()) {
cout << "b:" << *b << endl; } *c = 4; cout << "c:" << *c << endl; std::auto_ptr<int> d; d.reset(c); *d = 5; if (d.get()) {
cout << "d:" << *d << endl; } cout << "c:" << *c << endl; d.reset();//reset:若无参数直接释放,无返回值 if (d.get()) {
cout << "d:" << *d << endl; } getchar(); return 0; }
讯享网
二.unique_ptr
unique_ptr 由 C++11 引入,旨在替代不安全的 auto_ptr。unique_ptr 是一种定义在头文件中的智能指针。它持有对对象的独有权——两个unique_ptr 不能指向一个对象,即 unique_ptr 不共享它所管理的对象。它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL)算法。只能移动 unique_ptr,即对资源管理权限可以实现转移。这意味着,内存资源所有权可以转移到另一个 unique_ptr,并且原始 unique_ptr 不再拥有此资源。实际使用中,建议将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂。因此,当需要智能指针用于存 C++ 对象时,可使用 unique_ptr,构造 unique_ptr 时,可使用 make_unique Helper 函数。
相比于auto_ptr,其可以在编译期间合理确定智能指针对象作为右值时的合法性,只有作为临时右值才合法否则报错
讯享网unique_ptr<int> getUnique(int parm) {
unique_ptr<int> temp(new int(parm)); return temp; } int main() {
unique_ptr<int> a; //创建空智能指针 a.reset(new int); //绑定动态对象 *a = 1; cout << "a:" << *a << endl; *a = 2; unique_ptr<int>b = std::move(a);//所有权转移(通过移动语义),u_s所有权转移后,变成“空指针” if (a.get()) {
cout << "a:" << *a << endl; } cout << "b:" << *b << endl; *b = 3; unique_ptr<int> c; c.reset(b.release());//所有权转移 if (b.get()) {
cout << "b:" << *b << endl; } cout << "c:" << *c << endl; //unique_ptr<int> d = c; //编译出错,已禁止拷贝 //unique_ptr<int> d(c); //编译出错,已禁止拷贝 //unique_ptr<int> d; //d = c;//编译出错,已禁止赋值 unique_ptr<int> d = getUnique(1);//临时正确 getchar(); return 0; }
三 shared_ptr
shared_ptr 是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象,定义在 memory 文件中,命名空间为 std。shared_ptr最初实现于Boost库中,后由 C++11 引入到 C++ STL。shared_ptr 利用引用计数的方式实现了对所管理的对象的所有权的分享,即允许多个 shared_ptr 共同管理同一个对象。像 shared_ptr 这种智能指针,《Effective C++》称之为“引用计数型智能指针”(reference-counting smart pointer,RCSP)。
shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的),在使用引用计数的机制上提供了可以共享所有权的智能指针,当然这需要额外的开销:
(1)shared_ptr 对象除了包括一个所拥有对象的指针外,还必须包括一个引用计数代理对象的指针;
(2)时间上的开销主要在初始化和拷贝操作上, * 和 -> 操作符重载的开销跟 auto_ptr 是一样;
(3)开销并不是我们不使用 shared_ptr 的理由,,永远不要进行不成熟的优化,直到性能分析器告诉你这一点。
下面是一些成员函数及其简介
- swap:交换对象的指针
- reset:重置指针
- get:返回保存的指针
- operator*:解引用,得到对象
- use_count:引用计数
- unique:当前引用技术是否为1
- operator bool:检查是否为空
shared_ptr 没有release函数。
make_shared函数:
最安全的分配和使用动态内存的方法就是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。头文件和share_ptr相同,在memory中
int main() {
shared_ptr<int> a = make_shared<int>(1); std::shared_ptr<int> b(new int(2)); cout << "a:" << *a << endl; cout << "b:" << *b << endl; a.swap(b);//交换a和b cout << "a:" << *a << endl; cout << "b:" << *b << endl; cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; std::shared_ptr<int> c = a;//赋值 cout << "c:" << *c << endl; cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; cout << "c:Count:" << c.use_count() << endl; *b = 3; if (b.unique())//引用技术是否为1 {
cout << "b:" << *b << endl; } a.reset();//a 的引用计数为0 但是c还是可以使用 cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; cout << "c:Count:" << c.use_count() << endl; a.reset(new int(4)); cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; cout << "c:Count:" << c.use_count() << endl; getchar(); return 0; }
实现自己的智能指针
讯享网template <typename T> class Smarter; //辅助类 template <typename T> class Assistant {
private://全部私有 friend class Smarter<T>;//智能指针为友元,可以访问私有成员 Assistant(T* p) :data(p), nCount(1) {
} ~Assistant() {
delete data; } T* data; int nCount; }; template <typename T> class Smarter {
public: Smarter() {
}; Smarter(T* p) :pAssistant(new Assistant<T>(p)) {
} Smarter(const Smarter<T> &p) :pAssistant(p.pAssistant)//拷贝构造 {
++pAssistant->nCount; } Smarter& operator=(const Smarter<T> &p)//赋值构造 {
++p.pAssistant->nCount; if (pAssistant && --pAssistant->nCount == 0) delete pAssistant; pAssistant = p.pAssistant; return *this; } T& operator* () {
return *(pAssistant->data); } T* operator->() {
return pAssistant->data; } ~Smarter() {
std::cout << "nCount:" << pAssistant->nCount << std::endl; if (--pAssistant->nCount == 0) {
std::cout << "即将销毁" << std::endl; delete pAssistant; } } int count() {
if (pAssistant) return pAssistant->nCount; return 0; } private: Assistant<T> *pAssistant; }; int main() {
int *a = new int(1); {
Smarter<int> b = a; {
Smarter<int> c = b; {
Smarter<int> d; d = c; cout << "a:" << *a << endl; } cout << "a:" << *a << endl; } cout << "a:" << *a << endl; } cout << "a:" << *a << endl; getchar(); return 0; }
四std::weak_ptr
weak_ptr 被设计为与 shared_ptr 共同工作,可以从一个 shared_ptr 或者另一个 weak_ptr 对象构造而来。weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,它更像是 shared_ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator* 和 operator-> ,因此取名为 weak,表明其是功能较弱的智能指针。它的最大作用在于协助 shared_ptr 工作,可获得资源的观测权,像旁观者那样观测资源的使用情况。观察者意味着 weak_ptr 只对 shared_ptr 进行引用,而不改变其引用计数,当被观察的 shared_ptr 失效后,相应的 weak_ptr 也相应失效。
下面是一些成员函数及其简介
- weak_ptr w; //创建空 weak_ptr,可以指向类型为 T 的对象
- weak_ptr w(sp); //与 shared_ptr 指向相同的对象,shared_ptr 引用计数不变。T必须能转换为 sp 指向的类型
- w=p; //p 可以是 shared_ptr 或 weak_ptr,赋值后 w 与 p 共享对象
- w.reset(); //将 w 置空
- w.use_count(); //返回与 w 共享对象的 shared_ptr 的数量
- w.expired(); //若 w.use_count() 为 0,返回 true,否则返回 false
- w.lock(); //如果 expired() 为 true,返回一个空 shared_ptr,否则返回非空 shared_ptr
int main() {
std::shared_ptr<int> a; a.reset(new int(1)); std::weak_ptr<int> b = a; cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; std::shared_ptr<int> c; if (!b.expired())//检查是否过期 {
c = b.lock(); *c = 2; } cout << "a=" << *a << endl; cout << "c=" << *c << endl; cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; cout << "c:Count:" << c.use_count() << endl; cout << endl; std::weak_ptr<int> d = b; cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; cout << "c:Count:" << c.use_count() << endl; cout << "d:Count:" << d.use_count() << endl; cout << endl; b.reset(); cout << "a:Count:" << a.use_count() << endl; cout << "b:Count:" << b.use_count() << endl; cout << "c:Count:" << c.use_count() << endl; cout << "d:Count:" << d.use_count() << endl; getchar(); return 0; }
讯享网class Woman; class Man {
private: std::weak_ptr<Woman> m_wife; //std::shared_ptr<Woman> m_wife; public: void setWife(std::shared_ptr<Woman> woman) {
m_wife = woman; } ~Man() {
std::cout << "kill man\n"; } }; class Woman {
private: std::weak_ptr<Man> m_husband; //std::shared_ptr<Man> m_husband; public: void setHusband(std::shared_ptr<Man> man) {
m_husband = man; } ~Woman() {
std::cout << "kill woman\n"; } }; int main(int argc, char** argv) {
{
std::shared_ptr<Man> m(new Man()); std::shared_ptr<Woman> w(new Woman()); if (m && w) {
m->setWife(w); w->setHusband(m); } } getchar(); return 0; }
如果将Man和Woman对象内的私有成员换成shared_ptr;那么他们就互相引用了,当作用域结束后,他们的引用技术仍然不为0,造成内存泄露。
五 boost库scope_ptr
因为一个作用域指针只是简单保存和独占一个内存地址,所以 boost::scoped_ptr 的实现就要比 std::auto_ptr 简单。 在不需要所有权传递的时候应该优先使用 boost::scoped_ptr 。 在这些情况下,比起 std::auto_ptr 它是一个更好的选择,因为可以避免不经意间的所有权传递。
int main() {
boost::scoped_ptr<int> a(new int); *a = 1; *a.get() = 2; a.reset(new int); //boost::scoped_ptr<int> b = a;//不允许 retur 0; }
六 、boost库scoped_array
作用域数组,同scope_ptr,也是独享所有权的。
七 如何选择智能指针
(1)如果程序要使用多个指向同一个对象的指针,应选择 shared_ptr。这样的情况包括:
- 将指针作为参数或者函数的返回值进行传递的话,应该使用 shared_ptr;
- 两个对象都包含指向第三个对象的指针,此时应该使用 shared_ptr 来管理第三个对象;
- STL 容器包含指针。很多 STL 算法都支持复制和赋值操作,这些操作可用于 shared_ptr,但不能用于unique_ptr(编译器发出 warning)和 auto_ptr(行为不确定)。
(4)在局部作用域(例如函数内部或类内部),且不需要将指针作为参数或返回值进行传递的情况下,如果对性能要求严格,使用 scoped_ptr 的开销较 shared_ptr 会小一些。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/127511.html