智能指针+“这个”被认为有害吗?

时间:2008-12-19 20:45:26

标签: c++ pointers this smart-pointers shared-ptr

在使用智能指针的C ++项目中,例如boost::shared_ptr,使用“ this ”有什么好的设计理念?

考虑一下:

  • 存储任何智能指针中包含的原始指针以供以后使用是危险的。您已放弃对对象删除的控制,并信任智能指针,以便在适当的时间执行此操作。

  • 非静态类成员本质上使用 this 指针。它是一个原始指针,无法更改。

如果我将this存储在另一个变量中或将其传递给另一个可能存储它以供日后使用或在回调中绑定它的函数,我会创建当任何人决定进行共享时引入的错误指向我班级的指针。

鉴于此,我何时适合明确使用this指针?是否存在可以防止与此相关的错误的设计范例?

8 个答案:

答案 0 :(得分:13)

错误的问题

  

在使用智能指针的C ++项目中

这个问题实际上与智能指针无关。这只是关于所有权。

智能指针只是工具

他们没有改变所有权的概念,特别是。 需要在您的计划中拥有明确的所有权,所有权可以自愿转移,但不能由客户承担。

你必须明白智能指针(也包括锁和其他RAII对象)代表一个值和一个WRT这个值的关系。 shared_ptr是对对象的引用并建立关系:在此shared_ptr之前不得销毁该对象,并且当此shared_ptr被销毁时,如果它是最后一个别名对象,必须立即销毁对象。 (unique_ptr可以被视为shared_ptr的特殊情况,根据定义,其中存在零别名,因此unique_ptr始终是别名对象的最后一个。)

为什么要使用智能指针

建议使用智能指针,因为它们只表达了很多变量和函数声明。

智能指针只能表达定义明确的设计,它们不会消除定义所有权的需要。相反,垃圾收集消除了定义谁负责内存释放的需要。 (但不要忽视定义谁负责其他资源清理的需要。)

即使在非纯函数式垃圾收集语言中,您也需要明确所有权:如果其他组件仍需要旧值,则不希望覆盖对象的值。在Java中尤其如此,其中可变数据结构的所有权概念在线程程序中非常重要。

原始指针怎么样?

使用原始指针并不意味着没有所有权。它只是没有变量声明描述。它可以在评论,设计文档等中进行描述。

这就是为什么许多C ++程序员认为使用原始指针而不是足够的智能指针是劣等:因为它的表达力较差(我故意避免使用“好”和“坏”这两个术语)。我相信Linux内核在使用一些C ++对象来表达关系时会更具可读性。

您可以使用或不使用智能指针来实现特定设计。适当地使用智能指针的实现将被许多C ++程序员认为是优越的。

你的真实问题

  

在C ++项目中,使用“this”的优秀设计理念是什么?

那太模糊了。

  

存储原始指针以供以后使用是危险的。

为什么需要指针供以后使用?

  

您已放弃对对象删除的控制,并信任负责的组件在合适的时间执行此操作。

实际上,某些组件负责变量的生命周期。你不能承担责任:必须转移。

  

如果我将它存储在另一个变量中或者将其传递给另一个可能存储它以供以后使用或者在回调中绑定它的函数,我就会创建在任何人决定使用我的类时引入的错误。

显然,由于调用者没有被告知该函数将隐藏指针并在以后使用它而没有调用者的控制,因此您正在创建错误。

解决方案显然是:

  • 将责任转移到处理对象的生命周期
  • 确保指针仅在调用者
  • 的控制下保存和使用

仅在第一种情况下,您可能最终在类实现中使用智能指针。

问题的根源

我认为您的问题是您正在努力使用智能指针使问题复杂化。智能指针是使事情变得更容易而不是更难的工具。如果智能指针使您的规范变得复杂,那么就简单的事情重新考虑您的规范。

在遇到问题之前,不要尝试将智能指针作为解决方案。

仅引入智能指针来解决特定明确定义的问题。因为您没有描述特定明确定义的问题,无法讨论特定解决方案(涉及智能指针与否)。

答案 1 :(得分:12)

虽然我没有一般性答案或一些习语,但有boost::enable_shared_from_this。它允许您获取一个shared_ptr来管理已由shared_ptr管理的对象。因为在成员函数中你没有引用那些管理shared_ptr的函数,所以enable_shared_ptr允许你获得一个shared_ptr实例,并在你需要传递this指针时传递它。

但是这不能解决从构造函数中传递this的问题,因为当时没有shared_ptr管理你的对象。

答案 2 :(得分:5)

在operator ++()和operator<<()等函数中正确使用的一个例子是return *this;

答案 3 :(得分:5)

当您使用智能指针类时,直接公开“this”是危险的。有一些与boost::shared_ptr<T>相关的指针类可能有用:

  • boost::enable_shared_from_this<T>
    • 提供让对象返回指向自身的共享指针的能力,该指针使用与指向对象的现有共享指针相同的引用计数数据
  • boost::weak_ptr<T>
    • 与共享指针一起使用,但不保存对象的引用。如果所有共享指针都消失并且对象被释放,则弱指针将能够告诉该对象不再存在并且将返回NULL而不是指向无效内存的指针。您可以使用弱指针来获取指向有效引用计数对象的共享指针。

当然,这些都不是万无一失的,但它们至少会使您的代码更加稳定和安全,同时为您的对象提供适当的访问和引用计数。

答案 4 :(得分:1)

如果您需要使用this,请明确使用它。智能指针只包装它们拥有的对象的指针 - 独占(unique_ptr)或以共享方式(shared_ptr)。

答案 5 :(得分:1)

我个人喜欢在访问类的成员变量时使用 this 指针。例如:

void foo::bar ()
{
    this->some_var += 7;
}

这只是一个无害的风格问题。有些人喜欢它,有些人不喜欢。

但是将 this 指针用于任何其他事情可能会导致问题。如果你真的需要用它做一些奇特的东西,你应该重新考虑你的设计。我曾经看过一些代码,在类的构造函数中,它将this指针指向另一个存储在其他地方的指针!那真是太疯狂了,我无法想到这样做的理由。顺便说一下,整个代码是一个巨大的混乱。

你能告诉我们你想用指针做什么吗?

答案 6 :(得分:1)

另一种选择是使用侵入式智能指针,并在对象本身内处理引用计数,而不是指针。这需要更多的工作,但实际上更有效,更容易控制。

答案 7 :(得分:0)

传递此问题的另一个原因是,如果要保留所有对象的中央注册表。在构造函数中,对象使用此方法调用注册表的静态方法。它对各种发布/订阅机制很有用,或者当您不希望注册表需要了解系统中的对象/类时。