C++ Boost shared_ptr共享指针详细讲解

   2023-02-09 学习力0
核心提示:目录一、提要二、智能指针boost::shared_ptr与boost::scoped_ptr三、智能指针 boost::shared_ptr用法示例1示例2示例3示例4示例5一、提要boost::shared_ptr是另一个智能指针,与 boost::scoped_ptr有很大不同,本文阐述这种区别。二、智能指针boost::shared_pt

一、提要

boost::shared_ptr是另一个智能指针,与 boost::scoped_ptr有很大不同,本文阐述这种区别。

二、智能指针boost::shared_ptr与boost::scoped_ptr

主要区别在于:

  • boost::shared_ptr 不一定是对象的独占所有者。
  • 所有权可以与 boost::shared_ptr 类型的其他智能指针共享。在这种情况下,共享对象不会被释放,直到引用该对象的共享指针的最后一个副本被销毁。
  • 因为 boost::shared_ptr 可以共享所有权,所以可以复制智能指针,而这对于 boost::scoped_ptr 是不可能的。

boost::shared_ptr定义在boost/shared_ptr.hpp.

三、智能指针 boost::shared_ptr用法

示例1

基本调用boost::shared_ptr

示例 1

#include <boost/shared_ptr.hpp>
#include <iostream>
int main()
{
  boost::shared_ptr<int> p1{new int{1}};
  std::cout << *p1 << '\n';
  boost::shared_ptr<int> p2{p1};
  p1.reset(new int{2});
  std::cout << *p1.get() << '\n';
  p1.reset();
  std::cout << std::boolalpha << static_cast<bool>(p2) << '\n';
}

示例 1 使用了 boost::shared_ptr 类型的两个智能指针 p1 和 p2。 p2 用 p1 初始化,这意味着两个智能指针共享同一个 int 对象的所有权。当在 p1 上调用 reset() 时,一个新的 int 对象被锚定在 p1 中。这并不意味着现有的 int 对象被销毁。由于它也锚定在 p2 中,因此它继续存在。在调用 reset() 之后,p1 是编号为 2 的 int 对象的唯一所有者,而 p2 是编号为 1 的 int 对象的唯一所有者。

boost::shared_ptr 在内部使用引用计数器。只有当 boost::shared_ptr 检测到智能指针的最后一个副本已被销毁时,才会使用 delete 释放包含的对象。

与 boost::scoped_ptr 一样,boost::shared_ptr 重载 operator bool()、operator*() 和 operator->()。成员函数 get() 和 reset() 用于检索当前存储的地址或存储新地址。

作为第二个参数,可以将删除器传递给 boost::shared_ptr 的构造函数。删除器必须是一个函数或函数对象,它接受实例化时使用的 boost::shared_ptr 类型的指针作为其唯一参数。在析构函数中调用删除器而不是删除。这使得管理 boost::shared_ptr 中动态分配的对象以外的资源成为可能。

示例2

boost::shared_ptr用户自定义删除

示例 2

#include <boost/shared_ptr.hpp>
#include <Windows.h>
int main()
{
  boost::shared_ptr<void> handle(OpenProcess(PROCESS_SET_INFORMATION, FALSE,
    GetCurrentProcessId()), CloseHandle);
}

在示例2 boost::shared_ptr 被实例化为 void。传递给构造函数的第一个参数是 OpenProcess() 的返回值。 OpenProcess() 是一个用于获取进程句柄的 Windows 函数。在示例中,OpenProcess() 返回当前进程的句柄 - 示例本身。

Windows 使用句柄来引用资源。一旦不再使用资源,必须使用 CloseHandle() 关闭句柄。 CloseHandle() 期望的唯一参数是要关闭的句柄。在示例中,CloseHandle() 作为第二个参数传递给 boost::shared_ptr 的构造函数。 CloseHandle() 是句柄的删除器。当在 main() 结束时销毁句柄时,析构函数调用 CloseHandle() 以关闭作为第一个参数传递给构造函数的句柄。

示例2 之所以有效,是因为 Windows 句柄被定义为 void*。如果 OpenProcess() 没有返回 void* 类型的值,并且如果 CloseHandle() 没有预期 void* 类型的参数,则无法在此示例中使用 boost::shared_ptr。删除器不会使 boost::shared_ptr 成为管理任意资源的灵丹妙药。

示例3

boost::make_shared

#include <boost/make_shared.hpp>
#include <typeinfo>
#include <iostream>
int main()
{
  auto p1 = boost::make_shared<int>(1);
  std::cout << typeid(p1).name() << '\n';
  auto p2 = boost::make_shared<int[]>(10);
  std::cout << typeid(p2).name() << '\n';
}

Boost.SmartPointers 在 boost/make_shared.hpp 中提供了一个辅助函数 boost::make_shared()。使用 boost::make_shared(),您可以创建 boost::shared_ptr 类型的智能指针,而无需自己调用 boost::shared_ptr 的构造函数。

boost::make_shared() 的优点是必须动态分配的对象内存和智能指针内部使用的引用计数器的内存可以保留在一个块中。使用 boost::make_shared() 比调用 new 来创建动态分配的对象并在 boost::shared_ptr 的构造函数中再次调用 new 来为引用计数器分配内存更有效。

您也可以对数组使用 boost::make_shared()。在示例 1.5 中第二次调用 boost::make_shared() 时,一个具有十个元素的 int 数组被锚定在 p2 中。

boost::shared_ptr 自 Boost 1.53.0 起仅支持数组。 boost::shared_array 提供了一个类似于 boost::shared_ptr 的智能指针,就像 boost::scoped_array 类似于 boost::scoped_ptr 一样。当使用 Visual C++ 2013 和 Boost 1.53.0 或更高版本构建时,示例 1.5 为 p2 打印 class boost::shared_ptr<int [0]>。

从 Boost 1.53.0 开始,boost::shared_ptr 支持单个对象和数组,并检测是否必须使用 delete 或 delete[] 释放资源。因为 boost::shared_ptr 还重载了 operator[](自 Boost 1.53.0 起),所以这个智能指针是 boost::shared_array 的替代方案。

示例4

boost::shared_array

Example 4 .Using

#include <boost/shared_array.hpp>
#include <iostream>
int main()
{
  boost::shared_array<int> p1{new int[1]};
  {
    boost::shared_array<int> p2{p1};
    p2[0] = 1;
  }
  std::cout << p1[0] << '\n';
}

boost::shared_array 补充 boost::shared_ptr:由于 boost::shared_array 在析构函数中调用 delete[],所以这个智能指针可以用于数组。对于早于 Boost 1.53.0 的版本,boost::shared_array 必须用于数组,因为 boost::shared_ptr 不支持数组。

boost::shared_array 在 boost/shared_array.hpp 中定义。

在示例4 中,智能指针 p1 和 p2 共享动态分配的 int 数组的所有权。当使用 operator[] 访问 p2 中的数组以存储数字 1 时,使用 p1 访问相同的数组。因此,该示例将 1 写入标准输出。

与 boost::shared_ptr 一样,boost::shared_array 使用引用计数器。当 p2 被销毁时,动态分配的数组不会被释放,因为 p1 仍然包含对该数组的引用。只有当 p1 的作用域结束时,该数组才会在 main() 结束时被销毁。

boost::shared_array 还提供了成员函数 get() 和 reset()。此外,它使运算符 operator bool 过载。

示例5

boost::shared_ptrBOOST_SP_USE_QUICK_ALLOCATOR

Example5.boost::shared_ptrBOOST_SP_USE_QUICK_ALLOCATOR

#define BOOST_SP_USE_QUICK_ALLOCATOR
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <ctime>
int main()
{
  boost::shared_ptr<int> p;
  std::time_t then = std::time(nullptr);
  for (int i = 0; i < 1000000; ++i)
    p.reset(new int{i});
  std::time_t now = std::time(nullptr);
  std::cout << now - then << '\n';
}

选择像 boost::shared_ptr 这样的智能指针而不是标准库中的智能指针是有意义的。 Boost.SmartPointers 支持宏来优化智能指针的行为。示例 5 使用宏 BOOST_SP_USE_QUICK_ALLOCATOR 来激活 Boost.SmartPointers 附带的分配器。此分配器管理内存块以减少对引用计数器的 new 和 delete 调用次数。该示例调用 std::time() 来测量循环前后的时间。虽然执行循环所需的时间取决于计算机,但使用BOOST_SP_USE_QUICK_ALLOCATOR 的示例可能会比不使用时运行得更快。 Boost.SmartPointers 的文档没有提到 BOOST_SP_USE_QUICK_ALLOCATOR。因此,您应该分析您的程序并比较使用和不使用 BOOST_SP_USE_QUICK_ALLOCATOR 获得的结果。

Chapter1.Boost.SmartPointers - Shared Ownership (theboostcpplibraries.com)

原文地址:https://yamagota.blog.csdn.net/article/details/127045943
 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Aurelius vs mORMot vs EntityDAC Delphi 的
    Aurelius vs mORMot vs EntityDAC   Delphi 的 ORM框架:http://www.tmssoftware.com/site/aurelius.asp#product-buy-onlinehttps://synopse.info/fossil/wiki/Synopse+OpenSourcehttps://www.devart.com/entitydac/download.htmlkbmMW  http://www.compo
    02-09
  • 【Ruby】Mac gem的一些坑
    前言自上一次升级MacOS系统后出现jekyll无法构建的问题,当时处理半天。谁知道最近又升级了MacOS,荒废博客多时,今天吝啬写了一篇准备发布,构建报错,问题重新。还是记录下,以防下次升级出问题。问题描述安装jekyll静态博客需要在Ruby环境下运行,于是参照
    02-09
  • iOS oc 调用 swift
    如股票oc要调用swift里面的代码 需要包含固定这个头文件项目名称 LiqunSwiftDemo-Swift.h         #ProjectName#-Swift.h固定的写法swift 目的 是取代oc 但是 不会完全取代 只是前端的替换LiqunSwiftDemo-Swift 点进去 可以看到 所有的swift代码 都产生
    02-09
  • objective-c NSTimer 定时器
    -(void)initTimer{//时间间隔NSTimeInterval timeInterval =3.0 ;//定时器repeats 表示是否需要重复,NO为只重复一次NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(mobileAnimation) userInfo:nil
    02-09
  • Objective-C  日记③ 字符串
    Objective-C 日记③ 字符串
    一、创建字符串、类方法   公式创建NSString  +(id) stringWithFormat:(NSString *) format,……;eg:  NSString *height;  height=[NSString stringWithFormat:@"高度是: %d 长度: %d",10,20];得到的字符串:“高度是: 10 长度: 20” 注意:  省
    02-09
  • Objective-C KVC机制
    Objective-C KVC机制http://blog.csdn.net/omegayy/article/details/7381301全部推翻重写一个版本,这是我在公司内做技术分享的文档总结,对结构、条理做了更清晰的调整。 1.    基本概念MODEL主要是英文文档里面经常出现的一些概念,讲解一下,方便英文
    02-09
  • objective-c 加号 减号 - +
    “加号代表static”是错误的说法,可能跟你那样表达的人其实意思是:“前置加号的方法相当于Java 里面的静态方法”。在Oc中,方法分为类方法和实例方法。前置加号(+)的方法为类方法,这类方法是可以直接用类名来调用的,它的作用主要是创建一个实例。有人把
    02-09
  • Objective-C  日记①
    Objective-C 日记①
    1、Xcode的.m扩展名表示文件含有Object-C代码,C以.c文件,C++以.cpp文件2、头文件声明:C使用:#include,O-C使用#import(当然你也可以使用#include) 3、输出方式:  C:printf("",参数);  O-C:NSLog(@"",参数); 4、布尔类型  C:bool 具有true
    02-09
  • ASP.NET MVC 操作AD 获取域服务器当前用户姓
    #region 根据当前登录域账号 获取AD用户姓名和所在OU目录/// summary/// 根据当前登录域账号 获取AD用户姓名和所在OU目录/// /summary/// param name="searchUser"要搜索的当前用户名/param/// param name="paths"out返回该用户所在OU目录/param/// param nam
    02-09
  • swift和OC - 拆分数组 和 拆分字符串
    1. 拆分数组 /// 根据 数组 截取 指定个数返回 多个数组的集合func splitArray( array: [Date], withSubSize subSize: Int) - [[Date]] {//数组将被拆分成指定长度数组的个数let count = array.count% subSize == 0 ? (array.count/ subSize) : (array.count
    02-08
点击排行