c++ boost 库中提供的share_ptr(智能指针)

c++ boost 库中提供的share_ptr(智能指针)
转载 2017年07月28日 15:32:30
标签:
智能指针 /
share_ptr
112
共享指针 (shared_ptr) 是现在的 Boost 库中提供的,并且应该是将来 C++1x 的标准库中提供的一个模板类。在此之前,ISO/IEC 14882:2003 标准库 <memory> 中的“自动指针 (auto_ptr)”也有类似的功能。显然 shared_ptr 要比 auto_ptr 从功能上来说应该强大一些。这篇文章主要介绍 shared_ptr 的最基本用法和注意事项,相当于入门级多一点点。
1. shared_ptr 的功能
shared_ptr 主要的功能是,管理动态创建的对象的销毁。它的基本原理就是记录对象被引用的次数,当引用次数为 0 的时候,也就是最后一个指向某对象的共享指针析构的时候,共享指针的析构函数就把指向的内存区域释放掉。
共享指针对象重载了 operator* 和 operator-> , 所以你可以像通常的指针一样使用它。这部分不再赘述。
2. shared_ptr 所在库
2.1. 对于 Visual C++ 2010
目前,Visual C++ 2010 的 <memory> 库里,已经包含了 shared_ptr 模板类,也就是说,你可以直接这样写:
#include <memory>
2.2. 对于其它支持 ISO/IEC 14882:2003 标准的编译器
而 GNU G++ 的标准库中还没有支持(毕竟是将来的标准),如果在 G++ 中想使用 shared_ptr, 还是得用到 Boost 库,就是说,在 G++ 里,你得这样写:
#include <boost/shared_ptr.hpp>
3. shared_ptr 的构造
保险起见,你应该仅从以下几种途径构造一个共享指针(以下例子中若没特殊说明,T 就代表共享指针所指向的对象的类型):
3.0. 使用空参数构造函数构造
也就是说,你可以直接定义一个 shared_ptr 而不指定构造函数的内容:
1 shared_ptr<T> ptr;
这样做的话,ptr 的意义就相当于一个 NULL 指针。当你试图在一个空指针上做类似于 *ptr 或者 ptr->xx 之类的东西的时候,应该会收到异常的。
3.1. 直接从 new 操作符的返回值构造
用代码来表示,就是可以这样使用:
1 shared_ptr<T> ptr(new T());
3.2. 使用复制构造函数(或等号重载),从其它 shared_ptr 的对象构造
一种显然的情况是这样的:
1
2 shared_ptr<T> ptr1(new T()); // 本行与 3.1. 中的构造方法是一样的
shared_ptr<T> ptr2(ptr1);    // 这就是使用复制构造函数的方法,会让引用计数加 1
还有,shared_ptr 可以当作函数的参数传递,或者当作函数的返回值返回,这个时候其实也相当于使用复制构造函数。
3.3. 从 shared_ptr 提供的类型转换 (cast) 函数的返回值构造
shared_ptr 也可以类型转换,有关类型转换的详情参见下面的 5. 此处假设 B 是 A 的子类,那么,在 C 语言中 B 的指针当然是可以转换成 A 的指针的。在共享指针里,应该这样做:
1
2 shared_ptr<B> ptrb(new B());
shared_ptr<A> ptra( dynamic_pointer_cast<A>(ptrb) );
4. shared_ptr 的“赋值”
shared_ptr 也可以直接赋值,但是必须是赋给相同类型的 shared_ptr 对象,而不能是普通的 C 指针或 new 运算符的返回值。当共享指针 a 被赋值成 b 的时候,如果 a 原来是 NULL, 那么直接让 a 等于 b 并且让它们指向的东西的引用计数加 1; 如果 a 原来也指向某些东西的时候,如果 a 被赋值成 b, 那么原来 a 指向的东西的引用计数被减 1, 而新指向的对象的引用计数加 1. 就是说以下代码是允许的:
1
2
3 shared_ptr<T> a(new T());
shared_ptr<T> b(new T());
a = b; // 此后 a 原先所指的对象会被销毁,b 所指的对象引用计数加 1
shared_ptr 的对象在构造之后,可以被赋予空值,此时使用的应该是 reset() 函数,如:
1
2 shared_ptr<T> a(new T());
a.reset(); // 此后 a 原先所指的对象会被销毁,并且 a 会变成 NULL
当然理论上也可以这样写:
1
2 shared_ptr<T> a(new T());
a = shared_ptr<T>(); // 相当于给 a 赋一个新构造的 shared_ptr, 也就是 NULL
  注意:reset()函数是重置函数,如果括号内部参数为空,则相应的智能指针则变为空,若内部有参数。如:
[cpp] view plain copy
1. <span style="color:#ff0000;"> </span> int* a=new int(2);    
2.    int* b=new int(3);    
3. shared_ptr<int> sp2(a);    
4. shared_ptr<int> sp1(a);    
5. shared_ptr<int> sp(a);    
6.    sp.reset(b);  


使得sp获得b的拥有权。失去a的拥有权。注意这会使得a的拥有者少1.当a的拥有者变为0时,就会释放a的资源。
5. shared_ptr 的类型转换
shared_ptr 有两种类型转换的函数,一个是 static_pointer_cast, 一个是 dynamic_pointer_cast. 其实用法真的和 C++ 提供的 static_cast 和 dynamic_cast 很像,再结合 3.3. 的代码和以下类似的代码,几乎没什么好讲的:
1
2
3 shared_ptr<A> ptra;
shared_ptr<B> ptrb(new B());
ptra = dynamic_pointer_cast<A>(ptrb);
6. 从 shared_ptr 的对象获得传统 C 指针
很简单,可以这样用:
1
2 shared_ptr<T> ptr(new T());
T *p = ptr.get(); // 获得传统 C 指针
7. shared_ptr 的常见的其它用法
比如,“我想让一个已经构造好的共享指针,丢弃掉原来所指的对象(或者让其引用计数减 1),然后指向一个新的 new 出来的对象,该怎么办?”参考如下代码:
1
2 shared_ptr<T> ptr(new T());
ptr.reset(new T()); // 原来所指的对象会被销毁
8. shared_ptr 的错误用法
一定要注意,本节所述所有方法,都是错误的!
8.1. 在“中途”使用传统 C 指针构造共享指针
所谓在中途,指的就是不从 new 的返回值直接构造共享指针,比如从 this 指针构造自己的共享指针等。
8.2. 从一个对象的传统 C 指针,构造出两个或以上的共享指针
其实这种和 8.1. 也是类似的,或者说,这种情况是 8.1. 的一种具体情况,比如,下面的代码是错误的:
1
2
3 T *a = new T();
shared_ptr<T> ptr1(a);
shared_ptr<T> ptr2(a);
这样的话,ptr1 和 ptr2 的引用计数是单独算的,它们任意一个对象在析构的时候,都会销毁 a 所指的对象,所以,这个对象会被“销毁两次”。
9. shared_ptr 的局限
有关运行效率的问题在这里就不讨论了。其它方面,shared_ptr 的构造要求比较高,如果对象在创建的时候没有使用共享指针存储的话,之后也不能用共享指针管理这个对象了。如果有引用循环 (reference cycle), 也就是对象 a 有指向对象 b 的共享指针,对象 b 也有指向对象 a 的共享指针,那么它们都不会被析构。当然的,shared_ptr 也没有办法和 Garbage Collecting 比较,毕竟如果运行库能够干预,还是有算法可以检查到引用循环的。(例如求强连通分量的算法。)
尤其,在类的成员函数的编写的时候,有时我们经常希望得到“自己”的共享指针,但是这往往是无法得到的。此时也不能够从 this 指针构造自己的共享指针(参见 8.1.),所以有时很憋闷。
10. 总结
实际上上面这么多注意事项,中心思想就是一个:让 shared_ptr 正确地记录对象被引用次数。如果能悟出一点 shared_ptr 的工作原理,基本上不会弄出太危险的事情来。
void Dialog::sharedPtrInVector()函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Boost库中shared_ptr是一个智能指针,用于管理动态分配的对象。要用C语言实现shared_ptr,需要实现以下功能: 1. 一个结构体用于存储指向动态分配对象的指针以及计数器。 2. 函数用于创建一个新的共享指针,增加计数器,并将结构体指针返回。 3. 函数用于销毁一个共享指针,减少计数器,并在计数器为0时释放指向动态分配对象的指针。 需要注意的是,C语言没有自动垃圾回收机制,因此需要手动管理内存。此外,使用shared_ptr时要小心避免出现循环引用的问题。 总体来说,用C语言实现shared_ptr是一项复杂的任务,需要对内存管理和指针操作有深入的理解。建议使用现成的智能指针实现,如std::shared_ptr。 ### 回答2: 在C语言中实现Boost库的shared_ptr是一项相当有挑战性的任务,因为Boost库是使用C++编写的,利用其丰富的语言特性来实现shared_ptr智能指针功能。 为了实现类似的智能指针功能,我们可以使用C语言中的结构体和函数指针来模拟类和成员函数的概念。 首先,我们可以创建一个名为shared_ptr的结构体,其中包含一个指向资源的指针和一个指向资源的计数器指针。计数器用于跟踪当前资源被多少shared_ptr对象共享。 接下来,我们创建一系列的操作函数,例如构造函数、析构函数、拷贝构造函数和赋值运算符等。 在构造函数中,我们需要初始化shared_ptr对象,并将资源指针和计数器指针分配内存。同时,我们需要将计数器的初始值设置为1。 在析构函数中,我们需要释放资源指针并减少计数器的值。当计数器为0时,表示资源没有被任何shared_ptr对象所引用,我们需要释放计数器指针。 在拷贝构造函数和赋值运算符中,我们需要增加计数器的值,并在资源不再被任何shared_ptr对象引用时释放资源和计数器。 除了上述操作函数外,我们还可以实现一些辅助函数,例如获取资源指针、获取资源计数器和重载箭头操作符等。 总之,实现Boost库的shared_ptr功能是一项复杂而繁琐的任务,在C语言中需要使用结构体和函数指针来模拟C++中的类和成员函数。这只是一个简单的概述,实际实现过程可能会更加复杂和困难。 ### 回答3: 通过C语言实现boost库的share_ptr可以参考以下步骤: 1. 首先,我们需要定义一个结构体来表示share_ptr,包含两个成员变量,一个是指向被共享的数据的指针(例如int*),另一个是一个整数计数器,用于记录有多少个共享指针指向该数据。 ```c typedef struct{ void* pdata; int count; } share_ptr; ``` 2. 接下来,我们需要编写一系列的函数来操作share_ptr。首先是构造函数,用于创建一个新的share_ptr实例。在构造函数中,我们先将计数器初始化为1,然后将数据指针赋值给share_ptr的成员变量。 ```c share_ptr* share_ptr_create(void* pdata){ share_ptr* sp = (share_ptr*)malloc(sizeof(share_ptr)); sp->pdata = pdata; sp->count = 1; return sp; } ``` 3. 然后,我们需要编写一个增加引用计数的函数,用于创建指向相同数据的新的share_ptr。在该函数中,我们只需要将计数器加一即可。 ```c void share_ptr_add_ref(share_ptr* sp){ sp->count++; } ``` 4. 接下来,我们需要编写一个减少引用计数的函数,用于销毁share_ptr。在该函数中,我们首先将计数器减一,然后判断计数器是否为0,如果为0,表示没有其他share_ptr指向该数据,我们可以安全地释放该数据指针。 ```c void share_ptr_release(share_ptr* sp){ sp->count--; if(sp->count == 0){ free(sp->pdata); free(sp); } } ``` 5. 最后,我们需要编写一个获取数据指针的函数,用于在需要时访问被共享的数据。 ```c void* share_ptr_get(share_ptr* sp){ return sp->pdata; } ``` 通过以上的步骤,我们就可以用C语言实现一个简单的share_ptr类似于boost库中share_ptr。当然,boost库中share_ptr还有更多的功能和特性,这只是一个简单的实现示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值