【问题标题】:C++ (14) and manual memory managementC++ (14) 和手动内存管理
【发布时间】:2014-04-10 15:29:49
【问题描述】:

我刚刚收到一条评论,喜欢

问题在于手动内存管理。 delete 在用户代码中没有位置,从 C++14 开始,new 也没有

谁能解释一下为什么?

【问题讨论】:

  • 虽然其中有一点道理,但就目前而言,这种说法是完全错误的,所以不要要求解释。它与“宏在程序中没有位置”和“模板导致膨胀”或任何此类绝对教条一样错误。教条,不管什么是愚蠢的,它只告诉你追求它的狂热者的有限心态。
  • @Damon 我不是该声明的作者,但完全同意。你有没有在用户代码中出现deletenew 是最佳选择的示例?
  • @Damon 你能解释一下为什么它是“完全错误的”吗?
  • @KonradRudolph:这是错误的,因为它是那些教条式的笼统陈述之一。即使它适用于绝大多数情况(我并不怀疑),“没有位置”仍然是完全错误的。
  • 我已经编写了二十年来使用指针在 c'tors 中获取和在 d'tors 中释放的代码。而且我可以肯定地说,我从来没有因为在那里使用原始指针而发生内存泄漏或取消引用错误。不要误会我的意思,我当然有这些,但是因为我忘记初始化一个对象或忘记将它从某个容器中移除,等等。永远不会因为类中的原始指针未从析构函数等中正确删除。虽然智能指针很有帮助,但笼统地说没有其他有效方法只是谎言。

标签: c++ memory-management c++14


【解决方案1】:

警告:我支持这个答案,因为我认为它提供了一种最佳实践,可以改进约 95% 的 C++ 代码——甚至可能更多。也就是说,请阅读完整 cmets 以讨论一些重要的注意事项。

因为这是我的评论,这里是 my presentation 解释这一点。

简而言之:

[原始] 指针 必须。不是。自己的。 资源。

它容易出错且不必要,因为我们有更好的资源管理方法,从而减少错误、更短、更易读的代码以及对代码正确性的更高信心。在经济方面:它们的成本更低。

关于我发表的评论更具体:

从 C++11 开始(现已推出两年,并在相关部分由所有现代编译器实现),完全不需要手动删除内存(除非您编写 very 低级内存处理代码),因为您总是可以使用智能指针,而且通常甚至不需要它们(参见演示文稿)。但是,C++11 在实例化新的std::unique_ptr 时仍然要求您使用new。在 C++14 中,函数 std::make_unique 使 new 的这种用法变得不必要。因此,它也不再需要了。

可以说在代码中仍有一个位置-new,但这是 (a) 与普通 new 完全不同的情况,尽管语法相似,并且 (b) 在大多数情况下都可以替换使用allocator::construct 函数的情况。


James 指出了我老实忘记的这条规则的一个例外:当一个对象管理它自己的生命周期时。我会冒昧地说,这在大多数情况下并不常见,因为对象的生命周期可以总是在外部进行管理。但是,在某些应用程序中,将对象与其余代码分离并让它自行管理可能是有益的。在这种情况下,您需要动态分配对象并使用delete this 释放它。

【讨论】:

  • @James 幻灯片展示了 例经常使用动态分配的情况。这些幻灯片虽然没有声称完整性,但很容易涵盖典型代码中 new 的 99% 的用例。然而,除了幻灯片之外,我确实声明完整性(参见上面的 cmets)。你为什么不给出一个论点,为什么坚持智能指针是一种反模式? (但请注意,我根本不坚持这一点,而是坚持自动资源管理——这比我个人很少使用的智能指针更通用)。
  • @KonradRudolph 在适当的地方使用智能指针不是反模式。反模式试图在您使用动态分配的任何地方使用它们。
  • @Konrad:我想我之前和詹姆斯讨论过这种事情。在我看来,他主要以一种我认为不是真正规范的风格进行编程(不打算作为批评)。在这种风格中,实体对象通常(总是?)在智能指针和容器封装的意义上不被其他实体“拥有”。这有点像编写状态机来代替结构化的控制流。实体在正确的时间被销毁是程序结构的一个属性,而不是直接归因于释放它们的特定所有者(甚至是共享所有者组)。
  • @James 幻灯片是故意煽动性的。他们是演示幻灯片,这是他们的工作。原因是,大多数 C++(甚至是经验丰富的)程序员都严重过度依赖手动内存管理,这让我非常抓狂,因为它极大地影响了代码质量。
  • @KerrekSB 我愿意。它违反了 SRP。我会通过std::unique_ptr<T[]> 实现vector,我觉得这应该是实现它的规范方式。另请参阅 Martinho 的有影响力的Rule of Zero article。正如我之前所说,非拥有的原始指针很好。
【解决方案2】:

应该使用Smart pointers,然后依次使用std::make_sharedstd::make_unique,因为当应用程序抛出异常等时,处理new/delete等更容易出错。

智能指针在使用时会自动删除(使用RAII),即使抛出异常也不像可能泄漏内存的new/delete

请参阅thisthis 了解更多信息

【讨论】:

  • 例外是一个完全被过度使用的比喻。这根本不是真正的原因。更重要的是,唯一指针使用类型系统来强制您始终知道谁负责资源,并且不会忘记清理。也就是说,表达式new T; 是一个错误;表达式make_unique<T>(); 不是。
  • 这当然是完全错误的。事实上,在用户代码中使用动态内存的最常见原因是不使用智能指针。
【解决方案3】:

引用的陈述唯一说的是这个人 谁说它真的不懂程序设计或方式 C++ 有效(以及在 C++ 中使用动态内存的方式)。这 声明定义了一个反模式,比什么都重要。

可能有种特定类型的应用程序 适用的;我目前正在处理的应用程序是其中之一。但 这不是通用的,在我从事的大多数应用程序中 过去,大部分删除都在用户代码中。 (那些 那些不在像std::vector这样的基本课程中。)

【讨论】:

  • 詹姆斯,你应该知道得更多。而且您的答复缺少任何近似的论点。它仅表明您过去编写的大多数代码都是典型的 C++ 代码。 - IE。不是很健壮。
  • @KonradRudolph 我确实知道得更多。 20 多年来,我从事过(并从头开始编写)许多 C++ 应用程序。唯一泄漏资源的是当我尝试遵循对所有内容使用智能指针的规则时。 (不可避免地会有循环。)有时智能指针是合适的,但这不是一般规则。 (例如,在很多应用程序中,大多数delete 将是delete this。)
  • 鉴于我(和其他人)使用 C++ 应用程序的经验,我严重怀疑您的说法(至少这对于行业来说是非常不典型的)。相反,我认为这是您注意到内存泄漏的唯一应用程序。也就是说,感谢delete this 示例。这是一个非常神秘的案例,我忘记了,但是当您在异步系统中工作时,它可能会定期发生。
  • @KonradRudolph 我过去编写的大多数应用程序都是大型服务器(主要是电话路由系统),它们每周 7 天、每天 24 小时运行多年,与传统的对停机时间的处罚(在一种情况下,每分钟 10,000 马克)。正如他们所说,布丁的证据在于吃。我可以放心地说这些应用程序没有泄漏内存。 (FWIW:应用程序确实在一些特定情况下使用了我的预标准共享指针。但仅在特定情况下。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 2014-01-03
  • 2011-05-04
  • 2013-12-23
  • 2020-10-10
  • 1970-01-01
  • 2013-04-25
相关资源
最近更新 更多