我在大学学到,你总是必须释放未使用的对象,但不是你实际执行的方式。例如,正确构建代码等等。关于如何在 C++ 中处理指针有什么通用规则吗?

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

有帮助吗?

解决方案

我曾使用过嵌入式 Symbian 操作系统,该操作系统为此提供了一个出色的系统,完全基于开发人员惯例。

  1. 只有一个对象会拥有指针。默认情况下,这是创建者。
  2. 所有权可以传承。为了指示所有权的传递,该对象作为方法签名中的指针传递(例如void Foo(Bar *zonk);)。
  3. 所有者将决定何时删除该对象。
  4. 要将对象传递给方法仅供使用,该对象将作为方法签名中的引用传递(例如void Foo(Bat &zonk);).
  5. 非所有者类可以存储对它们所提供的对象的引用(而不是指针),只有当它们可以确定所有者在使用过程中不会破坏它时。

基本上,如果一个类只是使用某些东西,它就会使用引用。如果一个类拥有某些东西,它就会使用指针。

这工作得很漂亮,使用起来很愉快。内存问题非常罕见。

其他提示

规则:

  1. 尽可能使用智能指针. 。Boost有一些好的.
  2. 如果您不能使用智能指针, 删除后取出指针.
  3. 切勿在不允许您使用规则 1 的地方工作。

如果有人不允许规则 1,请记住,如果您获取其他人的代码、更改变量名称并删除版权声明,则没有人会注意到。除非这是一个学校项目,否则他们实际上会使用相当复杂的工具来检查这种恶作剧。也可以看看, 这个问题.

我想在这里添加另一条规则:

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

我们发现,刚接触 C++ 的程序员,或者刚刚接触过 Java 等语言的程序员,似乎都会学习 new,然后在想要创建任何对象时都会痴迷地使用它,而不管上下文如何。当在函数内本地创建对象纯粹是为了做一些有用的事情时,这尤其有害。以这种方式使用 new 可能会损害性能,并且当忘记相应的删除时,很容易导致愚蠢的内存泄漏。是的,智能指针可以帮助解决后者,但它不会解决性能问题(假设在幕后使用 new/delete 或等效项)。有趣的是(也许吧),我们发现在使用 Visual C++ 时,删除通常比新建更昂贵。

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

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

一般来说,除非必要,否则避免从堆中分配。如果必须,请对长期存在且需要在代码的不同部分之间共享的对象使用引用计数。

有时你需要动态分配对象,但它们只会在一定的时间范围内使用。例如,在之前的项目中,我需要创建数据库模式的复杂内存中表示——基本上是对象的复杂循环图。然而,该图仅在数据库连接期间才需要,之后可以一次性释放所有节点。在这种情况下,我称之为“本地GC成语”的好模式。我不确定它是否有“官方”名称,因为这是我只在自己的代码中看到的东西,并且在可可中(请参阅 NS自动释放池 在 Apple 的 Cocoa 参考中)。

简而言之,您创建一个“收集器”对象,该对象保留指向您使用 new 分配的临时对象的指针。它通常与程序中的某个作用域相关联,要么是静态作用域(例如-- 作为实现 RAII 习惯用法的堆栈分配对象)或动态对象(例如——与数据库连接的生命周期相关,就像我之前的项目一样)。当“收集器”对象被释放时,它的析构函数会释放它指向的所有对象。

另外,像 DrPizza 一样,我认为不使用模板的限制太严格了。然而,在对 Solaris、AIX 和 HP-UX 的旧版本(就在最近 - 是的,这些平台仍然活跃在财富 50 强中)上进行了大量开发之后,我可以告诉您,如果您真的关心可移植性,那么您应尽可能少地使用模板。不过,将它们用于容器和智能指针应该没问题(这对我有用)。如果没有模板,我描述的技术实施起来会更加困难。它将要求“收集器”管理的所有对象都派生自一个公共基类。

你好,

我建议阅读 Scott Meyers 的“Effective C++”的相关部分。易于阅读,他还涵盖了一些有趣的陷阱,以吸引粗心的人。

我也对缺乏模板感到好奇。所以没有STL或Boost。哇。

顺便说一句,让人们就惯例达成一致是一个好主意。正如让每个人就 OOD 约定达成一致一样。顺便说一句,《Effective C++》的最新版本没有第一版中有关 OOD 约定的优秀章节,这很遗憾,例如诸如公共虚拟继承之类的约定 总是 建立“isa”关系模型。

  • 当您必须手动使用管理内存时,请确保在相同的范围/函数/类/模块中调用删除,例如:
  • 让函数的呼叫者分配由其填充的内存,请勿返回新的指针。
  • 始终在调用 new 的同一个 exe/dll 中调用 delete,否则可能会遇到堆损坏问题(不同的不兼容的运行时库)。

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

@Timbo 强调的所有要点在设计该基类时都很重要。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top