您的位置:首页 > 其它

智能指针shared_ptr

2017-02-09 18:34 246 查看
// 智能指针会自动释放所指向的对象。
// shared_ptr的应用场景是:程序需要在多个对象间共享数据

/* 先从应用场景入手吧,说矿工A发现了一个金矿。
* 然后矿工A喊来了矿工B,一起开采,不久后矿工A劳累过度死了。
* 矿工B继续开采着矿工A发现的金矿。
* 但是矿工B不久后得了尘肺病。
* 这时候如果矿工B喊来了矿工C,那矿工C就继续开采这个金矿,
* 如果矿工B至死都没有喊anyone,那么这个金矿不再被任何人发现。
*
* 我们来说说实现
* 每个矿工new一个对象,金矿new一个对象。
* 矿工死了就delte掉,金矿不再被发现也delte掉。
*
* 但是我们有没有可能让最后一个矿工死时,金矿被自动delte掉?
* 这样的话我们就不需要额外管理金矿对象了。
* 有可能啊,你用共享指针啊。
* 共享指针管理一个对象,管理一个引用计数。
* 每次对共享指针赋值和拷贝时,引用计数就加1。
* 当共享指针被销毁时,引用计数就减1。
* 这样就变成多个矿工间共享金矿数据了。
*
* 下面我们来说说引用计数递增的情况
* 1 用一个shared_ptr初始化另一个shared_ptr,肯定调用拷贝构造函数喽
* 2 用一个shared_ptr赋值另一个shared_ptr,肯定调用赋值函数喽
* 3 将shared_ptr作为参数传递给一个函数,这个也会调用拷贝构造函数
* 4 将shared_ptr作为函数的返回值,这个也会调用拷贝构造函数
*
* 下面我们来说说引用计数递减的情况
* 1 shared_ptr被销毁,参数出栈是被销毁的一种情况
* 2 给shared_ptr重新赋值
*
* 一旦一个shared_ptr的引用计数变为0,它就会自动释放所管理的对象。
*/

#include <iostream>
#include <memory>

using namespace std;

struct Gold
{
~Gold() {total = -1;}
int total{20};

Gold &operator--()
{
--total;
return *this;
}

const Gold operator--(int)
{
Gold tmp = *this;
--(*this);
return  Gold(tmp);
}
};

class Miner
{
public:
Miner() : gold(make_shared<Gold>()) {}

Miner(const Miner &miner)
{
gold = miner.gold;
}

void dig()
{
(*gold)--;
}

Gold *base()
{
return gold.get();
}

private:
shared_ptr<Gold> gold;
};

int main(int argc, char *argv[])
{
auto miner1 = new Miner;
auto miner2 = new Miner(*miner1);

// 代码执行到这里
// @表示地址 usecount是引用计数
// miner1的gold @0x605f40
// miner2的gold @0x605f40
// shared_ptr的usecount是2
// 可见miner1和miner2的gold指向同一个对象
// 引用计数正确

auto gold = miner2->base();

// 代码执行到这里
// gold @0x605f40

miner1->dig();
cout << gold->total << endl;
miner2->dig();
cout << gold->total << endl;
miner1->dig();
cout << gold->total << endl;

delete miner1;

// 代码执行到这里
// miner1的gold (null)
// miner2的gold @0x605f40
// shared_ptr的usecount是1
// 引用计数正确

miner2->dig();
cout << gold->total << endl;

delete miner2;

// 代码执行到这里
// miner1的gold (null)
// miner2的gold @0x605f20
// miner2管理的对象(@0x605f40) 已被销毁
// 调用了Gold的析构函数
// gold->totle值为-1
// 至于miner2的gold @0x605f20 ??
// 管它呢,反正已引用不到

cout << gold->total << endl;

int *p2;
{
auto p1 = make_shared<int>(5);
p2 = p1.get();

// 代码执行到这里
// p1 @0x605f60
// usecount是1
// p2 指向@0x605f60
}

// 代码执行到这里
// 代码块出栈了,p1被销毁
// usecount变为0,所以p1管理的对象也被销毁了
// ***这是为什么不建议用get的原因
// 虽然可以正确输出p2所指向的对象,但是这是不确定的
// p2就是所谓的野指针了
cout << *p2 << endl;

shared_ptr<int> p4;
{
auto p3 = make_shared<int>(5);
p4 = p3;

// 代码执行到这里
// p3 @0x605f60
// p4 @0x605f60
// usecount是2
}

// 代码执行到这里
// 代码块出栈了,p3被销毁
// usecount变为1,p3并未销毁所管理的对象
// p4所管理的对象可以正确输出
cout << *p4 << endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: