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

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

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

无水先生   2022-11-22 我要评论

一、提要

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)

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们