概念
智能指针
所谓的智能指针本质就是一个类模板,它可以创建任意的类型的指针对象,当智能指针对象使用完后,对象就会自动调用析构函数去释放该指针所指向的空间。
RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
- 不需要显式地释放资源。
- 采用这种方式,对象所需的资源在其生命期内始终保持有效。
四种智能指针
auto_ptr
auto_ptr 是通过由 new 表达式获得的对象,并在 auto_ptr 自身被销毁时删除该对象的智能指针。它可用于为动态分配的对象提供异常安全、传递动态分配对象的所有权给函数和从函数返回动态分配的对象。
复制 auto_ptr ,会复制指针并转移所有权给目标: auto_ptr 的复制构造和复制赋值都会修改其右侧参数,而且“副本”不等于原值。因为这些不常见的复制语义,不可将 auto_ptr 置于标准容器中
成员类型
-
成员类型 定义
element_type T -
成员函数
(构造函数) —— 创建新的 auto_ptr
(析构函数)——销毁 auto_ptr 和被管理对象
operator= —— 从另一 auto_ptr 转移所有权
operator auto_ptroperator auto_ptr_ref
转换被管理指针到指向另一类型的指针
get —返回指向被管理对象的指针
operator*operator-> -------访问被管理对象
reset-------替换被管理对象
release --------释放被管理对象的所有权
unique_ptr
std::shared_ptr 是通过指针保持对象共享所有权的智能指针。多个 shared_ptr 对象可占有同一对象。下列情况之一出现时销毁对象并解分配其内存:
◦最后剩下的占有对象的 shared_ptr 被销毁;
◦最后剩下的占有对象的 shared_ptr 被通过 operator= 或 ◦reset() 赋值为另一指针
◦(构造函数) 构造新的 shared_ptr
◦(析构函数)如果没有更多 shared_ptr 指向持有的对象,则析构对象
◦operator=对 shared_ptr 赋值
◦reset替换所管理的对象
◦swap 交换所管理的对象
◦get返回存储的指针
◦operator*operator->解引用存储的指针
◦use_count 返回 shared_ptr 所指对象的引用计数
◦operator bool 检查是否有关联的管理对象
◦owner_before提供基于拥有者的共享指针排序
std::weak_ptr
是一种智能指针,它对被 std::shared_ptr 管理的对象存在非拥有性(「弱」)引用。在访问所引用的对象前必须先转换为 std::shared_ptr。
std::weak_ptr 用来表达临时所有权的概念:当某个对象只有存在时才需要被访问,而且随时可能被他人删除时,可以使用 std::weak_ptr 来跟踪该对象。需要获得临时所有权时,则将其转换为 std::shared_ptr,此时如果原来的 std::shared_ptr 被销毁,则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。
◦(构造函数)构造新的weak_ptr
◦(析构函数) 销毁 weak_ptr
◦operator=为weak_ptr赋值
◦reset释放被管理对象的所有权
◦swap交换被管理对象
◦use_count 返回管理该对象的 shared_ptr 对象数量
◦expired检查被引用的对象是否已删除
◦lock 创建管理被引用的对象的shared_ptr
◦owner_before提供弱指针的基于拥有者顺序
std::unique_ptr 是通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。
在下列两者之一发生时用关联的删除器释放对象:
◦销毁了管理的 unique_ptr 对象
◦通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。
◦通过调用 get_deleter()(ptr) ,用潜在为用户提供的删除器释放对象。默认删除器用 delete 运算符,它销毁对象并解分配内存。
◦unique_ptr 亦可以不占有对象,该情况下称它为空 (empty)。
◦std::unique_ptr 有两个版本:
-
管理单个对象(例如以 new 分配)
-
管理动态分配的对象数组(例如以 new[] 分配)
shared_ptr
是通过指针保持对象共享所有权的智能指针。多个 shared_ptr 对象可占有同一对象。下列情况之一出现时销毁对象并解分配其内存:
◦最后剩下的占有对象的 shared_ptr 被销毁;
◦最后剩下的占有对象的 shared_ptr 被通过 operator= 或 reset() 赋值为另一指针。
用 delete 表达式或在构造期间提供给 shared_ptr 的定制删除器销毁对象。
shared_ptr 能在存储指向一个对象的指针时共享另一对象的所有权。此特性能用于在占有其所属对象时,指向成员对象。存储的指针为 get() 、解引用及比较运算符所访问。被管理指针是在 use_count 抵达零时传递给删除器者。
shared_ptr 亦可不占有对象,该情况下称它为空 (empty) (空 shared_ptr 可拥有非空存储指针,若以别名使用构造函数创建它)。
shared_ptr 的所有特化满足可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 和可小于比较 (LessThanComparable) 的要求并可按语境转换为 bool 。
成员函数
(构造函数)构造新的 shared_ptr
(析构函数) 如果没有更多 shared_ptr 指向持有的对象,则析构对象
operator= 对 shared_ptr 赋值
reset 替换所管理的对象
swap 交换所管理的对象
get 返回存储的指针
operator*operator-> 解引用存储的指针
use_count 返回 shared_ptr 所指对象的引用计数
operator bool 检查是否有关联的管理对象
owner_before提供基于拥有者的共享指针排序
make_sharedmake_shared_for_overwrite
allocate_sharedallocate_shared_for_overwrite
get_deleter返回指定类型中的删除器,若其拥有
operator<< 将存储的指针的值输出到输出流
std::swap(std::shared_ptr)特化 std::swap 算法
简单的实现一下shared_ptr 和weak_ptr
#include<iostream>
using namespace std;
class Counter{
public:
Counter(int scnt=1,int wcnt=0):scnt(scnt),wcnt(wcnt){
cout<<"Counter "<<endl;
}
int scnt,wcnt;
~Counter(){
cout<<"~Counter"<<endl;
}
};
template<class T>
class Wptr;
template<class T>
class Shpr{
public:
Shpr(T * ptr=nullptr):ptr(ptr){
if(ptr!=nullptr){
pct=new Counter(1,0);
}else{
pct=nullptr;
}
}
Shpr(const Shpr& sp):ptr(sp.ptr),pct(sp.pct){
if(pct!=nullptr){
pct->scnt++;
}
}
void reset(){
if(pct!=nullptr&&ptr!=nullptr){
--(pct->scnt);
if(pct->scnt==0){
delete ptr;
if(pct->wcnt==0){
delete pct;
}
}
}
pct=nullptr;
ptr=nullptr;
}
void reset(T *ptr){
reset();
this->ptr=ptr;
if(ptr!=nullptr){
pct=new Counter(1,0);
}
}
~Shpr(){
reset();
}
int use_count(){
return pct==nullptr?0:pct->scnt;
}
Shpr(Shpr &&sp){
ptr=sp.ptr;
pct=sp.pct;
sp.ptr=nullptr;
sp.pct=nullptr;
}
Shpr & operator=(Shpr &&sp){
if(ptr!=sp.ptr){
}
return *this;
}
T & operator *(){
return *ptr;
}
T * operator ->(){
return ptr;
}
operator bool(){
return ptr==nullptr;
}
friend class Wptr<T>;
private:
T* ptr;
Counter * pct;
};
template<class T>
class Wptr{
public:
Wptr(){
ptr=nullptr;
pct=nullptr;
}
Wptr(Shpr<T> &sp){
ptr=sp.ptr;
pct=sp.pct;
if(pct!=nullptr ){
pct->wcnt++;
}
}
void reset(){
if(pct!=nullptr){
--pct->wcnt;
if(pct->scnt==0&&pct->wcnt==0){
delete pct;
}
}
pct=nullptr;
ptr=nullptr;
}
~Wptr(){
reset();
}
Wptr(const Wptr<T>& wp){
ptr=wp.ptr;
pct=wp.pct;
if(pct!=nullptr){
pct->wcnt++;
}
}
Wptr(Wptr<T> && wp){
ptr=wp.ptr;
pct=wp.pct;
wp.ptr=nullptr;
wp.pct=nullptr;
}
Wptr& operator =(const Wptr<T> & wp){
if(ptr!=wp.ptr){
reset();
ptr=wp.ptr;
pct=wp.pct;
if(pct!=nullptr){
pct->wcnt++;
}
}
return *this;
}
Wptr& operator =(const Wptr<T> && wp){
if(ptr!=wp.ptr){
reset();
ptr=wp.ptr;
pct=wp.pct;
wp.ptr=nullptr;
wp.pct=nullptr;
}
}
Wptr& operator=(const Shpr<T>& sp){
reset();
ptr=sp.ptr;
pct=sp.pct;
if(sp.pct!=nullptr){
sp.pct->wcnt++;
}
}
int use_count(){
return pct==nullptr?0:pct->scnt;
}
bool expired(){
return pct==nullptr||pct->scnt==0;
}
Shpr<T> lock(){
Shpr<T> sp(ptr);
sp.ptr=ptr;
sp.pct=pct;
if(pct!=nullptr){
pct->scnt++;
}
return sp;
}
private:
T* ptr;
Counter * pct;
};
int main(){
Shpr<int> sp(new int(1002));
cout<<sp.use_count()<<endl;
{
Wptr<int> wp1(sp);
cout<<wp1.use_count()<<endl;
Shpr<int> sp1(sp);
cout<<sp1.use_count()<<endl;
}
cout<<sp.use_count()<<endl;
}
实现时需要注意一点,shared_ptr 和weak_ptr同时实现时,这两个智能指针类都需要有一个计数器的指针,这个计数器类里面(如果智能指针指向一个对象的话)要存指向这个对象的shared_ptr 和weak_ptr 的数量,之后要依据这两个数量来确定是否释放这个计数器,应该是当shared_ptr和weak_ptr的技术都为0时才释放。
本文详细介绍了C++中的智能指针概念,包括auto_ptr、unique_ptr、shared_ptr和weak_ptr,以及RAII技术的应用。通过实例演示了如何使用这些工具来自动管理内存,避免手动释放带来的问题,以及它们在生命周期控制和资源管理中的优势。
1719

被折叠的 条评论
为什么被折叠?



