c++ 之 shared_ptr

/*

* shared_ptr

*/

shared_ptr 是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个 shared_ptrs 共同指向一个对象。

这便是所谓的引用计数(reference counting)。

一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。

这在非环形数据结构中防止资源泄露很有帮助。

类似 vector 智能指针也是模板。

shared_ptr<string> p1; // shared_ptr,可以指向string

shared_ptr<list<int>> p2; // shared_ptr,可以指向int的list

智能指针的使用方法和普通指针类似,解引用返回它指向的对象,如果在一个条件判断中使用智能指针,效果就是检测它是否为空,

// 如果 p1 不为空,检查它是否指向一个空 string

if (p1 && p1->empty()) // p->mem -- (*p).mem

*p1 = "ds"

/*

* share_ptr 的拷贝和赋值

*/

当进行拷贝或赋值操作时,每个 shared_ptr 都会记录有多少个其他 shared_ptr 指向相同的对象:

auto p = make_shared<int>(42); // p指向的对象只有p一个引用者

auto q(p); // p和q指向相同对象,此对象有两个引用者

可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)。

无论何时拷贝一个shared_ptr,计数器都会递增;

当给shared_ptr赋予一个新值或是shared_ptr被销毁时,计算器就会递减。

一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象:

auto r = make_shared<int>(42); // r指向的int只有一个引用者

r = q; // 给r赋值,令它指向另一个地址

// 递增q指向的对象的引用计数

// 递减r原来指向对象的引用计数

// r原来指向的对象已没有引用者,会自动释放

/*

* share_ptr 自动销毁所管理的对象

*/

当指向一个对象最后一个 share_ptr 被销毁时,share_ptr 类会自动销毁此对象。

它是通过另一个特殊的成员函数------析构函数完成销毁工作的。

/*

* shared_ptr 和 new 结合使用

*/

可以使用 new 返回的指针来初始化智能指针,智能指针是一个类,分装了一个原始的 C++ 指针,用以管理所指对象的生命期。

shared_ptr<double> p1; // shared_ptr可以指向一个double

shared_ptr<int> p2(new int (42)); // p2指向一个值为42的int

接受指针参数的智能指针构造函数是 explicit 的。

因此,我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针:

shared_ptr<int> p1 = new int(1024); //错误:必须使用直接初始化形式

shared_ptr<int> p2(new int (1024)); //正确:使用了直接初始化

出于相同的原因,一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针:

shared_ptr<int> clone(int p) {

return new int(p); //错误:隐式转换为shared_ptr<int>

}

shared_ptr<int> clone(int p) {

return shared_ptr<int>(new int(p)); //正确:显式地用int*创建shared_ptr<int>

}

默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。

可以将智能指针绑定到一个指向其他类型的资源的指针上,但是为了这样做,必须提供操作来代替 delete 。

/*

* weak_ptr

*/

weak_ptr是为配合shared_ptr而引入的一种智能指针。

weak_ptr可以从一个shared_ptr或另一个weak_ptr对象构造,

它的构造和析构不会引起shared_ptr引用记数的增加或减少(但会导致引用计数区域内负责weak_ptr计数变量_M_weak_count的增加或减少,

当其计数为0时,调用_M_destroy()释放对象内存)。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象。

weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己,

但助手类enable_shared_from_this的shared_from_this会返回this的shared_ptr,只需要让想被shared_ptr管理的类从它继承即可。

/*

* example

*/

#include <iostream>

#include <memory>

#include <thread>

#include <chrono>

#include <mutex>

struct Base

{

Base() { std::cout << " Base::Base()\n"; }

// 注意:此处非虚析构函数 OK

~Base() { std::cout << " Base::~Base()\n"; }

};

struct Derived: public Base

{

Derived() { std::cout << " Derived::Derived()\n"; }

~Derived() { std::cout << " Derived::~Derived()\n"; }

};

void thr(std::shared_ptr<Base> p)

{

std::this_thread::sleep_for(std::chrono::seconds(1));

std::shared_ptr<Base> lp = p; // 线程安全,虽然自增共享的 use_count

{

static std::mutex io_mutex;

std::lock_guard<std::mutex> lk(io_mutex);

std::cout << "local pointer in a thread:\n"

<< " lp.get() = " << lp.get()

<< ", lp.use_count() = " << lp.use_count() << '\n';

}

}

int main()

{

std::shared_ptr<Base> p = std::make_shared<Derived>();

std::cout << "Created a shared Derived (as a pointer to Base)\n"

<< " p.get() = " << p.get()

<< ", p.use_count() = " << p.use_count() << '\n';

std::thread t1(thr, p), t2(thr, p), t3(thr, p);

p.reset(); // 从 main 释放所有权

std::cout << "Shared ownership between 3 threads and released\n"

<< "ownership from main:\n"

<< " p.get() = " << p.get()

<< ", p.use_count() = " << p.use_count() << '\n';

t1.join(); t2.join(); t3.join();

std::cout << "All threads completed, the last one deleted Derived\n";

}

#if 0

Base::Base()

Derived::Derived()

Created a shared Derived (as a pointer to Base)

p.get() = 0x56072b522260, p.use_count() = 1

Shared ownership between 3 threads and released

ownership from main:

p.get() = 0, p.use_count() = 0

local pointer in a thread:

lp.get() = 0x56072b522260, lp.use_count() = 6

local pointer in a thread:

lp.get() = 0x56072b522260, lp.use_count() = 4

local pointer in a thread:

lp.get() = 0x56072b522260, lp.use_count() = 2

Derived::~Derived()

Base::~Base()

All threads completed, the last one deleted Derived

#endif

相关推荐
醍醐三叶5 小时前
C++类与对象--2 对象的初始化和清理
开发语言·c++
wuqingshun3141597 小时前
蓝桥杯 16. 外卖店优先级
c++·算法·职场和发展·蓝桥杯·深度优先
海绵宝宝贾克斯儿7 小时前
C++中如何实现一个单例模式?
开发语言·c++·单例模式
Epiphany.5567 小时前
素数筛(欧拉筛算法)
c++·算法·图论
龙湾开发7 小时前
计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 10.增强表面细节(二)法线贴图
c++·笔记·学习·图形渲染·贴图
whoarethenext8 小时前
c/c++的opencv的轮廓匹配初识
c语言·c++·opencv
爱吃涮毛肚的肥肥(暂时吃不了版)8 小时前
项目班——0510——JSON网络封装
c++·算法·json
apocelipes8 小时前
使用libdivide加速整数除法运算
c语言·c++·性能优化·linux编程
虾球xz8 小时前
游戏引擎学习第290天:完成分离渲染
c++·人工智能·学习·游戏引擎
易只轻松熊8 小时前
C++(20): 文件输入输出库 —— <fstream>
开发语言·c++·算法