内存管理之智能指针shared_ptr

智能指针(smart pointer)


智能指针的行为类似常规指针,重要的区别在于智能指针负责自动释放所指向的对象,头文件memory
shared_ptr : 允许多个智能指针指向同一个对象
unique_ptr : 一个指针“独占”所指向的对象
weak_ptr : 弱引用,指向shared_ptr所管理的对象
 
 
shared_ptr:

1.创建一个shared_ptr,必须提供指针指向的类型,命名格式:shared_ptr<类型> 指针名;
例如:shared_ptr<string> sptr 或 shared_ptr<vector<int>> vctptr,上述形式的初始化,返回的智能指针中保存一个空指针
 
2.与普通指针相似,解引用(*)智能指针返回它指向的对象
 
3.shared_ptr支持的操作,参看c++ primer 5 Edition P401
 
4.make_shared函数:作为智能指针的初始化方式之一,安全的分配和使用动态内存。功能:在动态内存中,分配一个对象并初始化,返回此对象的shared_ptr,
格式:shared_ptr<类型> 指针名 = make_shared<类型>();例如:
shared_ptr<int> iptr = make_ptr<int>(); // 使用int的默认构造函数,初始化shared_ptr对象的内容
shared_ptr<int> iptr = make_ptr<int>(36); // 使用int的重载构造函数,初始化shared_ptr对象的内容为36

5.shared_ptr的拷贝和赋值

当拷贝和赋值操作时,每个shared_ptr都会记录有多少个其他的shared_ptr指向相同的对象,即:每个shared_ptr都有一个关联的计数器,引用计数;无论何时拷贝(赋值)一个shared_ptr,计数器都会递增。
 
递增的情况有三种(这里类似复制构造函数,存在的情形):
a.用一个shared_ptr初始化另外一个shared_ptr
b.作为函数参数传参(拷贝实参对象)
c.作为函数返回值(返回出来还是要赋值)
 
指向同一对象的所有shared_ptr指针的计数都相同,同时更新(+1或-1),一旦计数器变为0,则会自动释放shared_ptr所管理的对象
 
智能指针初始化方式:
shared_ptr<int> iptr = make_shared<int>(5);
cout << iptr.use_count() << endl;
shared_ptr<int> data = make_shared<int>(1); // 初始化方式1:make_shared
// shared_ptr<int> data(iptr); 初始化方式2:直接初始化
iptr = data; // 初始化方式3:赋值:智能指针之间相互赋值
cout << *iptr << endl;
cout << data.use_count() << endl;
智能指针只能用只能指针来初始化,或者相互赋值;不能用内置类型指针来赋值,可以用内置类型指针直接初始化
6.shared_ptr自动销毁管理对象,也会自动释放相关联的动态内存
 
指向一个对象的最后一个shared_ptr销毁时,shared_ptr类会自动销毁此对象,该类中有析构函数,shared_ptr的析构函数会自动递减它所指向的对象的引用计数,当变为0时,shared_ptr的析构函数就会销毁对象,并释放占用的内存。
对于一块内存,shared_ptr类保证只要有任何shared_ptr对象引用它,就不会被释放掉
 
例子1:
// func返回一个shared_ptr,指向一个动态分配的对象
shared_ptr<foo> func(T arg) {
    return make_shared<foo>(arg);
}
foo类,使用T类型参数arg,通过构造函数初始化一块内存,nake_shared函数将该内存地址返回给智能指针shared_ptr,
并作为函数func的返回值,返回一个shared_ptr,可以确保在函数体内申请的动态内存会在恰当的时刻被释放
例子2:
void func2(T arg) {
    shared_ptr<foo> p = make_shared<foo>(arg);
   // 使用p, 当p离开作用域,它指向的内存会被自动释放
}
例子3:
shared_ptr<foo> func3(T arg) {
    shared_ptr<foo> p = make_shared<foo>(arg);
    return p;  
    // 使用p,当返回p时,引用计数进行了递增操作,当p离开作用域,它指向的内存会被自动释放
}
return语句向此函数的调用者返回一个P的拷贝。拷贝一个shared_ptr会增加所管理的对象的引用计数值;当p销毁时,该内存还有其他使用者,内存就不会被释放

如果忘记了销毁程序不再需要的shared_ptr,程序仍然会正常运行,但是会浪费内存。shared_ptr在无用之后仍然保留的一种可能情况:shared_ptr放在容器中,然后重排了容器,从而不再需要某些元素,在这种情况下,应该erase删除不需要的shared_ptr指针。

 
7.shared_ptr一些初始化操作:直接内存管理(参考内存管理---直接内存管理)
前面5提到过shared_ptr的初始化,总结一下:
1.不进行初始化,会自动初始化为一个空指针nullptr
shared<类型> 指针名;例如:shared_ptr<int> pi;  
2.使用内置类型指针直接初始化
shared_ptr<类型> 指针名(内置类型指针p); 这里的p --> 类型* p = new 类型()
shared_ptr<类型> 指针名(new<类型>())// shared_ptr与new结合使用
3.shared_ptr<类型> 指针名(智能指针ptr); // 使用智能指针直接初始化
4.shared_ptr<类型> 指针名 = 智能指针ptr; //智能指针赋值初始化
5.shared_ptr<类型> 指针名 = make_shared<类型>(); // make_shared函数初始化
不能将一个内置指针隐式的转换成一个智能指针,必须使用直接初始化的形式
一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象
 
8.定义改变shared_ptr的其他方法  参看c++ primer 5 Edition P412-413
 
9.不要混合使用普通指针和智能指针
当一个shared_ptr绑定到一个普通指针时,就将内存的管理责任交给了shared_ptr
 
10.不要使用智能指针get()方法初始化另一个智能指针或者智能指针赋值
get()方法可以获取该智能指针的对应的内置指针,该内置指针指向智能指针管理的对象
使用get()返回的指针代码不能delete此指针,因为该返回的内置指针指向智能指针管理的对象,该对象的释放由智能指针来管理
 
11.智能指针和异常:智能指针可以保证当程序发生异常时,仍旧能正确的释放资源
原文地址:https://www.cnblogs.com/zhang716921/p/10626709.html