有没有理由使用原始指针来做RAII? C ++一十四分之一十一

时间:2014-06-25 16:25:35

标签: c++ pointers smart-pointers

在C ++ 11/14中是否有任何理由仍然使用原始指针(对于托管资源)?

类中的资源成员变量是否应该保存在自己的智能指针中,以便自动RAII而不需要在析构函数中进行清理?

智能指针的实现是否表明这样做没有开销?

3 个答案:

答案 0 :(得分:4)

  

还有任何理由仍然使用原始指针(对于托管   资源)在C ++ 11/14中?

我认为通过"托管资源"你的意思是拥有资源"。

是的,有理由:

  1. 正如您在问题中推断的那样,有时您想要引用某个对象或者没有引用该对象,并且它可以随时间变化。在这种情况下,您必须使用原始指针,因为在这种特定情况下现在没有替代方法。稍后可能会有一个关于添加" dumb"非拥有指针,它只是澄清指针的作用(观察/引用,而不是自己)。同时建议如果你可以避免新的/删除,只使用原始指针作为"指的是没有拥有"一种可重新分配的参考。
  2. 您仍然需要原始指针来实现非原始指针和任何低级RAII构造。并不是每个人都需要在基础库上工作,但是如果你这样做,那么你需要基本的构造来使用。例如,在我的域中,我经常需要构建自定义"对象池"系统以不同的方式。在实现的某些时候,你必须操作原始内存,而不是对象,所以你需要使用原始指针来处理它。
  3. 与C接口通信时,除了将原始指针传递给接受它们的函数之外别无选择。许多C ++开发人员必须这样做,因此只需要在代码的某些特定区域中使用它们。
  4. 大多数使用C ++的公司都没有现代的C ++"经验丰富的C ++,并使用大量指针的代码,而这些代码实际上并不是必需的。因此,大多数情况下,当您向代码库添加代码时,您可能会受到代码环境,政治,同行压力和公司惯例的强制要求使用更多现代c ++中的指针&# 34;使用类型的公司,它不会通过同行评审。因此,在选择技术时,请考虑同事的政治/历史/社会/知识基础。或者确保您工作的公司/项目符合您的工作方式(这可能更难)。
  5.   

    类中的资源成员变量是否应该保存在自己的智能中   自动RAII的指针,无需在析构函数中进行清理?

    在最好的情况下,资源成员变量应该只是成员而不是明显的指针,甚至不是智能指针。聪明的指针是一个桥梁"代码之间操纵原始指针和纯RAII风格。如果您完全控制某些代码及其新代码,则可以完全避免在界面中使用智能指针。也许你会在你的实现中需要它们。请记住,没有实际的规则,只有您可能会导致的建议

      

    智能指针的实现是否内联没有   这样做的开销呢?

    标准智能指针的实现尽可能高效,因此大多数代码都是内联的。但是,它们并不总是免费的,这取决于它们实际上做了什么。例如,在几乎所有情况下,unique_ptr都只是一个原始指针,只需在其周围进行额外的检查即可。所以它是免费的"。另一方面,shared_ptr必须维护一个计数器,其中有多少其他shared_ptr引用同一个对象。该计数器可以在几个执行shared_ptr副本的线程上更改,因此它必须是原子的。更改原子计数器的值并不总是免费的,您应该始终假设复制原始指针的成本更高。

    所以"它取决于"。

    只需:

    • 尽可能多地使用RAII,而不会在界面中暴露任何类型的指针(聪明与否);
    • 如果必须使用拥有指针,则在实现中使用标准智能指针;
    • 仅当您需要引用object,null或其他随时间变化的对象而不拥有它们时才使用原始指针;
    • 避免接口中的原始指针,除非允许传递可选对象(当nullptr是正确的参数时);

    从用户的角度来看,您最终会得到的代码似乎无法操纵指针。如果您遵循这些规则有多层代码,则代码将更易于遵循并且易于维护。

    来自When to use references vs. pointers

    的相关说明
      

    在你不能做之​​前避免使用指针。

    另请注意,Sean Parents在他最近的会谈中也认为智能指针是原始指针。它们确实可以封装为与被操纵的实际概念相对应的值 - 语义类型的实现细节。另外在实现中使用类型擦除技术但从未将它们暴露给用户有助于某些库构造的可扩展性。

答案 1 :(得分:0)

这取决于。如果对象是由另一个对象完全拥有,构造和销毁的,那么在另一个对象中使用std::unique_ptr是一个很好的例子。如果你有一个拥有几个这样的对象的对象,所有这些对象都是在构造函数中动态分配的,那么你必须做点什么;如果通常的智能指针的语义不合适(通常是这种情况),那么你必须发明一些东西:例如,在图形的情况下,你可以将根指针放入一个基类(将其初始化为null),并让基类的析构函数从根开始清理图形。

当然,除非您的类具有某种动态结构(如图形),否则您可能会问自己为什么要使用动态分配。有一些特殊情况(例如,拥有的对象是多态的,其实际类型取决于构造函数的参数),但根据我的经验,它们并不常见。实际上,在很多情况下,智能指针可以在对象中使用,更不应该使用。

答案 2 :(得分:0)

RAII不只是包装新的和删除 - 智能指针是RAII的一种形式,但RAII远不止于此。 RAII的一个很好的候选者是你有任何类型的镜像功能:新/删除,初始化/拆除,停止/启动。所以你的资源应该仍然有自己的RAII类 - 一个在自己的析构函数中执行清理功能的类。