以对象管理资源02
请记住:任何技术都是一层窗户纸,一捅就破。只是起了一个牛逼的名字而已,我们花老爷grape告诉我,再怎么花哨的技术,无非就是封装、继承、多态而已。话不多说开始本节的重点智能指针(以对象管理资源)。
自C++11起,C++标准提供两大类型的智能指针:
1. Class shared_ptr实现共享式拥有(shared ownership)概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用(reference)被销毁”时候释放。为了在结构复杂的情境中执行上述工作,标准库提供了weak_ptr、bad_weak_ptr和enable_shared_from_this等辅助类,但我们一般用的weak_ptr比较多
2. Class unique_ptr实现独占式拥有(exclusive ownership)或严格拥有(strict ownership)概念,保证同一时间内只有一个智能指针可以指向该对象。它对于避免资源泄露(resourece leak)——例如“以new创建对象后因为发生异常而忘记调用delete”——特别有用。
一.shared_ptr的使用
shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。
1. 智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一个是类,一个是指针。例如std::shared_ptr pp = new int(10);的写法是错误的.
2. get函数可以获取原始指针
3. 请不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存,导致出错。
看看下面的例子:
#include <iostream>
#include <memory>
int main() {
{
int a = 10;
std::shared_ptr<int> ptra = std::make_shared<int>(a);
std::shared_ptr<int> ptra2(ptra); //copy
std::cout << ptra.use_count() << std::endl;//2
int b = 20;
int *pb = &a;
//std::shared_ptr<int> ptrb = pb; //error
std::shared_ptr<int> ptrb = std::make_shared<int>(b);//1
ptra2 = ptrb; //assign
pb = ptrb.get(); //获取原始指针
std::cout << ptra.use_count() << std::endl;//1
std::cout << ptrb.use_count() << std::endl;//2
}
}
结果:
请继续看:
class A1
{
public:
A1(int x,int y)
{
a = x;
b = y;
}
void show()
{
cout << a << " " << b << endl;
}
int a, b;
~A1()
{
cout << "~A1\n";
}
};
void gogo()
{
//类
shared_ptr<A1>m_pp = make_shared<A1>(1, 2);
m_pp->show();
A1 *m_ap1 = new A1(100,200);
shared_ptr<A1>m_spap1(m_ap1);
m_spap1->show();
//普通类型
shared_ptr<int>m_pt = make_shared<int>(10);
cout << *m_pt << endl;
//int a = 20;
//shared_ptr<int> m_myp(&a);//注意这样是不行的因为变量a在栈区。
int *pa = new int(1000);
shared_ptr<int> m_spa(pa);
cout << *pa << endl;
}
int main() {
gogo();
system("pause");
}
结果:
二.unique_ptr的使用
unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。相比与原始指针unique_ptr用于其RAII的特性,使得在出现异常的情况下,动态资源能得到释放。unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)。unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。
#include <iostream>
#include <memory>
int main() {
{
std::unique_ptr<int> uptr(new int(10));
//std::unique_ptr<int> uptr2 = uptr; //不能赋值
//std::unique_ptr<int> uptr2(uptr); //不能复制
std::unique_ptr<int> uptr2 = std::move(uptr); //装换所有权
uptr2.release(); //释放所有权
}
}
继续看代码:
void gogog1()
{
unique_ptr<A1>m_pp(new A1(1, 2));
m_pp->show();
m_pp.release();//转换之后m_pp为空
m_pp->show();//会报错
}
当指针m_pp离开作用域后就会释放指针所指内存。