C ++内存管理

时间:2020-03-05 18:43:09  来源:igfitidea点击:

我在大学里了解到,我们始终必须释放未使用的对象,而不是实际的操作方式。例如,正确构造代码等。
关于如何在C ++中处理指针,是否有任何通用规则?

我目前不允许使用boost。我必须坚持使用纯c ++,因为我使用的框架禁止任何泛型的使用。

解决方案

回答

规则:

  • 尽可能使用智能指针。 Boost有一些不错的选择。
  • 如果无法使用智能指针,请在删除指针后将其清空。
  • 切勿在不允许我们使用规则1的地方工作。

如果有人禁止规则1,请记住,如果我们抓住别人的代码,更改变量名称并删除版权声明,则没有人会注意到。除非这是一个学校项目,否则他们实际上会使用非常复杂的工具检查这种恶作剧。另请参阅此问题。

回答

  • 当我们必须手动使用管理内存时,请确保在相同的作用域/功能/类/模块中调用delete,以先应用为准,例如:
  • 让函数的调用者分配由它填充的内存,而不返回新指针。
  • 始终在与调用new相同的exe / dll中调用delete,因为否则我们可能会遇到堆损坏(不同的不兼容运行时库)的问题。

回答

我使用的是嵌入式Symbian OS,它完全基于开发人员约定为该系统提供了出色的系统。

  • 只有一个对象将拥有一个指针。默认情况下,这是创建者。
  • 所有权可以转移。为了指示所有权的传递,该对象作为方法签名中的指针传递(例如void Foo(Bar * zonk);)。
  • 所有者将决定何时删除对象。
  • 要将对象传递给仅供使用的方法,该对象将作为方法签名中的引用传递(例如void Foo(Bat&zonk);)。
  • 非所有者类仅在可以确定所有者在使用过程中不会销毁它们的对象时,才可以存储对它们的引用(从不指向指针)。

基本上,如果一个类仅使用某些东西,它将使用引用。如果一个类拥有某些东西,它将使用一个指针。

效果很好,使用起来很愉快。内存问题非常罕见。

回答

在一般情况下(资源管理,其中资源不一定是内存),我们需要熟悉RAII模式。这是C ++开发人员最重要的信息之一。

回答

我们可以从实现智能指针之类的功能的某些基类派生所有内容(使用ref()/ unref()方法和计数器。

@Timbo突出显示的所有点在设计该基类时都很重要。

回答

G'day,

我建议阅读Scott Meyers撰写的" Effective C ++"的相关部分。易于阅读,他介绍了一些有趣的陷阱,可以避免不必要的麻烦。

缺少模板也让我着迷。因此没有STL或者Boost。哇。

顺便说一句,让人们就公约达成共识是一个好主意。就像使每个人都同意OOD的约定一样。顺便说一句,最新版本的有效C ++没有第一版中关于OOD约定的出色章节,例如,诸如公共虚拟继承之类的约定总是为" isa"关系建模。

回答

我会在这里添加另一个规则:

  • 当自动对象可以正常工作时,请勿新建/删除对象。

我们发现,对于C ++还是陌生的程序员,或者从Java之类的语言来的程序员似乎都了解了new,然后在无论上下文如何都想创建任何对象时都过分使用它。当纯粹在函数中本地创建对象以执行有用的操作时,这尤其有害。以这种方式使用new会对性能造成不利影响,并且在忘记相应的删除操作时,很容易造成愚蠢的内存泄漏。是的,智能指针可以帮助后者,但不能解决性能问题(假设在幕后使用了new / delete或者等效项)。有趣的是(也许),我们发现使用Visual C ++时,删除往往比新的要昂贵。

这种混乱的某些原因还在于,它们调用的函数可能将指针甚至智能指针作为参数(当引用可能会更好/更清晰时)。这使他们认为他们需要"创建"一个指针(很多人似乎认为这是new所做的事情)才能将指针传递给函数。显然,这需要一些有关如何编写API的规则,以使调用约定尽可能明确,并随函数原型提供的清晰注释得到加强。

回答

通常,除非必须,否则避免从堆中进行分配。如果必须的话,可以将引用计数用于寿命长的对象,并且需要在代码的不同部分之间共享。

有时我们需要动态分配对象,但是它们只会在一定时间范围内使用。例如,在上一个项目中,我需要创建数据库模式的复杂内存表示形式-基本是对象的复杂循环图。但是,仅在数据库连接期间才需要该图,此后可以一次释放所有节点。在这种情况下,我称之为"本地GC习惯用法"的一种好模式。我不确定它是否具有"正式"名称,因为这是我仅在自己的代码和Cocoa中看到的名称(请参阅Apple Cocoa参考中的NSAutoreleasePool)。

简而言之,我们将创建一个"收集器"对象,该对象保留指向使用new分配的临时对象的指针。它通常与程序中的某个范围相关联,例如静态范围(例如,作为实现RAII习惯的堆栈分配对象)或者动态范围(例如,与数据库连接的生存期绑定),就像我之前提到的那样。项目)。释放"收集器"对象后,其析构函数将释放它指向的所有对象。

此外,像DrPizza一样,我认为不使用模板的限制也很严格。但是,在Solaris,AIX和HP-UX的较旧版本上进行了大量开发(最近是的,这些平台在《财富》 50强中仍然存在),我可以告诉我们,如果我们真的关心可移植性,则应该尽可能少地使用模板。不过,将它们用于容器和智能指针应该没问题(对我有用)。没有模板,我描述的技术将很难实施。它将要求"收集器"管理的所有对象都源自一个公共基类。