什么是智能指针?何时应该使用智能指针?

2023-11-23

什么是智能指针?何时应该使用智能指针?


UPDATE

这个答案相当古老,因此描述了当时“好的”,即 Boost 库提供的智能指针。从 C++11 开始,标准库已经提供了足够的智能指针类型,因此您应该倾向于使用std::unique_ptr, std::shared_ptr and std::weak_ptr.

还有std::auto_ptr。它非常像作用域指针,只不过它还具有“特殊”危险的复制能力——这也会意外地转移所有权。
它在 C++11 中已弃用并在 C++17 中删除,所以你不应该使用它。

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

旧答案

智能指针是一个包装“原始”(或“裸”)C++ 指针的类,用于管理所指向对象的生命周期。没有单一的智能指针类型,但它们都尝试以实用的方式抽象原始指针。

智能指针应该优先于原始指针。如果您觉得需要使用指针(首先考虑您是否reallydo),您通常会希望使用智能指针,因为这可以缓解原始指针的许多问题,主要是忘记删除对象和泄漏内存。

使用原始指针,程序员必须在对象不再有用时显式销毁该对象。

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

相比之下,智能指针定义了有关何时销毁对象的策略。您仍然需要创建该对象,但不再需要担心销毁它。

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

使用的最简单的策略涉及智能指针包装对象的范围,例如由boost::scoped_ptr or std::unique_ptr.

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

注意std::unique_ptr实例无法复制。这可以防止指针被多次(错误地)删除。但是,您可以将对它的引用传递给您调用的其他函数。

std::unique_ptr当您想要将对象的生命周期绑定到特定的代码块时,或者如果您将其作为成员数据嵌入到另一个对象中(即另一个对象的生命周期)时,s 非常有用。该对象一直存在,直到包含的代码块退出,或者直到包含的对象本身被销毁。

更复杂的智能指针策略涉及指针的引用计数。这确实允许复制指针。当对该对象的最后一个“引用”被销毁时,该对象就被删除。该政策的实施由boost::shared_ptr and std::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

当对象的生命周期更加复杂并且不直接绑定到特定的代码部分或另一个对象时,引用计数指针非常有用。

引用计数指针有一个缺点——可能会创建悬空引用:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

另一种可能性是创建循环引用:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

为了解决这个问题,Boost 和 C++11 都定义了一个weak_ptr定义对 a 的弱(不可计数)引用shared_ptr.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是智能指针?何时应该使用智能指针? 的相关文章

随机推荐

  • 通用集合中的记录相等性

    假设您有一条带有重载相等运算符的记录 TSomeRecord record Value String class operator Equal Left Right TSomeRecord Boolean end 实现比较字符串值 如果根据
  • Linux中每个进程的最大线程数

    我编写了一个简单的程序来计算Linux Centos 5 中一个进程可以拥有的最大线程数 这是代码 int main pthread t thrd 400 for int i 0 i lt 400 i int err pthread cre
  • NuGet 包引用复制 dll 本地

    我需要将 NuGet dll 的 Copy Local 设置为 false 在此之前 我使用了包配置格式 一切正常 迁移到后封装参考格式 我找不到如何做到这一点的方法 有人可以帮助我吗 您可以使用私有资产 从文档复制
  • 使用 Hibernate API 进行 Java 字符串日期验证

    我正在尝试验证字符串日期 using javax validation 休眠验证 我需要检查给定的字符串日期应该是过去的并且它应该是正确的yyyyMMdd具有所有限制的格式 例如闰年 30th 31st day public class U
  • 如何捕获鼠标移动事件

    我想在我的主窗体中捕获鼠标移动事件 虽然我能够连接MouseEventHandler对于主窗体 当光标位于 UserControl 或任何其他控件上时 该事件不再触发 如何确保我始终掌握鼠标位置 您可以使用低级鼠标钩 看this示例并检查
  • 使用 ctypes 传递数组

    我有一个C函数 void read FIFO AI0 int16 t input size t size NiFpga Session session NiFpga Status status input int16 t malloc si
  • 如何使用 SWIG 扩展 python 中的模板化 C++ 类以允许 [] 运算符

    我有一个模板化的 C 数组类 它使用标准向量类 include
  • 向量点积计算的时间和空间复杂度

    计算两个长度为 n 的向量之间的点积的算法的时间和空间复杂度是多少 如果这 2 个向量是a a1 a2 an and b b1 b2 bn then 点积由下式给出a b a1 b1 a2 b2 an bn 为了计算这个 我们必须执行n乘法
  • 设置 tk.Frame 宽度和高度

    所以我正在创建一个 GUI 并尝试使其一切都适合屏幕 我已经画出了我希望 GUI 的每个部分的外观及其大小的粗略草图 因此我知道所有内容的粗略尺寸 然而 我遇到的第一个问题是设置屏幕的左半部分 所以左半部分由一个框架组成 我们称之为Main
  • 如何替换已弃用的 ggplot2 函数 aes_string:接受任意数量的命名字符串来指定美学映射?

    aes string我在使用 ggplot2 编程时使用了一些方便的行为 但aes string已被弃用 我相信是从 ggplot2 版本 3 4 0 开始 我正在努力思考如何很好地替换它 具体来说 我之前创建了通过省略号接受任意字符串参数
  • 错误 403:scrapy 中未处理或不允许 HTTP 状态代码

    这是我为抓取 justdial 网站而编写的代码 import scrapy from scrapy http request import Request class JustdialSpider scrapy Spider name j
  • WebRTC - 在通信过程中更改视频流

    我的目标是使用 webrtc Web 应用程序在视频或音频通话中启用屏幕共享 好吧 我发现我可以使用MediaStreamTrack applyConstraints 更改视频属性 但是否可以更改视频源 进一步说明如何将视频添加到现有音频流
  • 从 C++ 调用 C# 方法而不使用 COM

    有没有办法创建 C 对象并从非托管 C 调用方法 但不使用 COM Iterop 我正在寻找类似 JNI 但适用于 Net 的东西 您可以在其中手动创建 VM 创建对象等 如果您使用 C CLI 那么您可以直接与托管世界和非托管代码交互 因
  • Python Selenium“WebDriver”对象没有属性错误

    我正在尝试从中文网站上抓取一些由 javascript 生成的内容 我正在使用 Selenium 和 Python 因为我无法直接抓取 javascript 内容 coding utf 8 from selenium import webd
  • Pandas:按满足条件的列进行分组

    我有一个包含三列的数据集 评级 品种和狗 import pandas as pd dogs breed Chihuahua Chihuahua Dalmatian Sphynx dog True True True False rating
  • 获取 Chrome 浏览器的最新发布版本号

    我正在尝试找出一种相当稳定的方法来以编程方式确定 chrome 浏览器的最新发行版本号 它不必是万无一失的 因为它只是一个很好的功能 每当结果看起来 可疑 时我就可以混合出来 似乎没有 API 有吗 我不想依赖第三方手动处理这些事情 我不想
  • “按 NULL 排序”是什么意思

    我使用 oracle 11g 下面的 line order by null 意味着什么 select f value row number over order by null as id from tableName The OVER 条
  • 如何使用 Python 以 Gmail 作为提供商发送电子邮件?

    我正在尝试使用 python 发送电子邮件 Gmail 但出现以下错误 Traceback most recent call last File emailSend py line 14 in
  • 通过 MySQL 数据库更改发送 WebSocket 更新哪个更有效

    我目前正在尝试使用 WebSockets 以减少 消除在潜在的低带宽环境中对持续 AJAX 请求的需求 所有设备都兼容 WebSocket 所以没有问题 我试图将其保留为原生 PHP WebSocket 没有 Node js 或其他框架 库
  • 什么是智能指针?何时应该使用智能指针?

    什么是智能指针 何时应该使用智能指针 UPDATE 这个答案相当古老 因此描述了当时 好的 即 Boost 库提供的智能指针 从 C 11 开始 标准库已经提供了足够的智能指针类型 因此您应该倾向于使用std unique ptr std