有什么理由使用原始指针来做RAII吗?c++ 11/14

Any reason to use raw pointers to do RAII? C++11/14

本文关键字:RAII c++ 理由 什么 指针 原始      更新时间:2023-10-16

在c++ 11/14中仍然使用原始指针(用于管理资源)有什么原因吗?

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

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

有什么理由仍然使用原始指针吗资源)在c++ 11/14?

我认为你所说的"管理资源"是指"拥有的资源"。

是有原因的:

  1. 正如你在问题中所推断的,有时你想指一个对象或没有对象,它可以随着时间而改变。在这种情况下,你必须使用原始指针,因为在这种特殊情况下,目前没有其他选择。稍后可能会有一个关于添加一个"哑"非拥有指针的建议,它只是澄清了指针的角色(观察/引用,而不是拥有)。同时,建议尽量避免new/delete,并将原始指针仅用作"不拥有的引用"类型的可重新分配引用。
  2. 您仍然需要原始指针来实现非原始指针和任何低级RAII结构。并不是每个人都需要使用基本的库,但是如果您需要,那么您需要使用基本的构造。例如,在我的领域中,我经常不得不以不同的方式构建自定义的"对象池"系统。在实现的某些时候,你必须操作还不是对象的原始内存,所以你需要使用原始指针来处理它。
  3. 当与C接口通信时,除了将原始指针传递给接受它们的函数外,别无选择。很多c++开发人员都必须这样做,所以只有在代码的一些非常特定的区域,你才能使用它们。
  4. 大多数使用c++的公司都没有"现代c++"的c++经验,并且在代码中使用了大量不必要的指针。所以大多数时候,当你向他们的代码库添加代码时,你可能会被代码环境、政治、同行压力和公司惯例所强迫使用指针,而在更"现代"的c++使用类型的公司中,它不会通过同行评审。所以在选择技巧时也要考虑同事的政治/历史/社会/知识背景。或者确保你工作的公司/项目符合你做事的方式(这可能更难)。

类中的资源成员变量应该保存在它们自己的智能中吗指针自动RAII不需要在析构函数清理?

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

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

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

所以"视情况而定"

:

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

从用户的角度来看,你最终得到的代码似乎并没有操作指针。如果你有几层代码遵循这些规则,代码将更容易遵循和高度可维护。

关于:何时使用引用与指针

尽量避免使用指针。

还请注意,Sean Parents在他最近的演讲中也认为智能指针是原始指针。它们确实可以被封装为值语义类型的实现细节,对应于被操作的实际概念。此外,在实现中使用类型擦除技术但不向用户公开它们有助于某些库结构的可扩展性。

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

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

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