1
76
将指针设置为0(在标准C++中为“NULL”,C的NULL定义有点不同)避免了双删除中的崩溃。 请考虑以下几点:
鉴于:
换句话说,如果不将已删除指针设置为0,则在执行双重删除时会遇到问题。反对在delete之后将指针设置为0的一个参数是,这样做只是屏蔽了两个delete错误,并使它们未被处理。 显然,最好不要有双重删除错误,但是依赖于所有权语义和对象生命周期,这在实践中很难实现。比起ub,我更喜欢蒙面的双重删除错误。
最后,关于管理对象分配,我建议您看看
|
2
53
删除指针后将指针设置为空肯定不会造成伤害,但这通常是一个更基本的问题上的创可贴:为什么首先要使用指针?我可以看到两个典型的原因:
我的经验法则是,如果你在用户代码中留下指针,你就错了。指针本来就不应该指向垃圾。为什么没有一个对象负责确保其有效性?为什么它的作用域在指向对象时没有结束? |
3
42
我有一个更好的最佳实践:尽可能结束变量的作用域!
|
4
27
我总是把指针指向
我还将其他类型的资源句柄设置为当资源空闲时的no resource值(通常仅在为封装资源而编写的raii包装的析构函数中)。 我做了一个大的(900万份声明)商业产品(主要是C语言)。有一次,当内存释放时,我们使用宏魔术将指针清空。这立即暴露了许多潜伏的虫子,并迅速修复。据我所知,我们从未有过双重自由的错误。 更新: 微软认为这是一个很好的安全实践,并在sdl策略中推荐了这种实践。显然msvc++11会 stomp the deleted pointer 如果使用/sdl选项编译,则自动(在许多情况下)。 |
5
12
首先,在这方面和相关话题上存在很多问题,例如 Why doesn't delete set the pointer to NULL? . 在你的代码中,问题发生在(使用p)。例如,如果在某个地方有这样的代码:
然后将p设置为null几乎没有什么效果,因为您仍然需要担心指针p2。 这并不是说将指针设置为空总是毫无意义的。例如,如果p是指向资源的成员变量,而该资源的生存期与包含p的类不完全相同,则将p设置为null可能是指示资源存在或不存在的有用方法。 |
6
7
如果在
这个比喻的目的是提醒程序员,在运行时,对象已经被删除了。 一个更好的实践是使用智能指针(共享或作用域)自动删除其目标对象。 |
7
3
正如其他人所说,
我确信在某个地方使用指针作为标志有一种代码味道,但我还没有找到。 |
8
2
我会稍微改变一下你的问题:
有两种情况可以跳过将指针设置为空:
同时,在我看来,将指针设置为空可能会隐藏错误,这听起来像是在争论不应该修复错误,因为修复可能会隐藏另一个错误。如果指针未设置为空,则可能显示的唯一错误是试图使用指针的错误。但如果将其设置为空,实际上会导致与在释放内存的情况下使用它时所显示的完全相同的错误,不是吗? |
9
2
如果没有其他强制您在删除指针后设置或不将其设置为空的约束(其中一个约束由 Neil Butterworth ),那么我个人的偏好是留下它。 对我来说,问题不是“这是个好主意吗?”但是“我会通过这样做来阻止或允许什么行为成功?”例如,如果这允许其他代码看到指针不再可用,那么为什么其他代码在释放指针之后还要试图查看它们呢?通常是虫子。 它也做了比必要更多的工作,并且妨碍了事后调试。当你不需要记忆的时候,你接触的记忆越少,就越容易弄清楚为什么会有东西崩溃。很多时候,我都依赖于这样一个事实,即内存的状态与某个特定的错误发生时的状态相似,以诊断和修复所说的错误。 |
10
2
在delete之后显式为空强烈地向读者建议指针表示概念上 可选择的 . 如果我看到了这一点,我就会开始担心,在源代码中指针使用的任何地方,都应该首先对null进行测试。 如果这就是你真正的意思,那么最好在源代码中使用类似于 boost::optional
但如果你真的想让人们知道指针“坏了”,我会百分之百同意那些说最好的办法是让它超出范围的人。然后使用编译器来防止在运行时出现错误的解引用。 这就是所有C++中的婴儿,不应该扔掉它。:) |
11
2
在具有适当错误检查的结构良好的程序中,没有理由
不
指定为空。
反对分配的许多论据
如果程序员想要引入一个指针的使用,这个指针可能是空的,作为一个特殊的值,并写下所有必要的回避,这是他们故意引入的一个复杂问题。隔离越好,你越早发现误用案例,它们传播到其他程序中的能力就越小。 结构良好的程序可以使用C++特性来设计,以避免这些情况。您可以使用引用,也可以只说“传递/使用空参数或无效参数是一个错误”——这种方法同样适用于容器,如智能指针。不断增加的一致性和正确的行为会阻止这些错误的发展。 从那里,您只有一个非常有限的作用域和上下文,其中可能存在(或允许)空指针。
同样的方法也适用于
最后,您的编译器和环境可能有一些保护措施,以防出现错误(涂鸦)、检测对已释放内存的访问以及捕获其他相关ub的情况。您还可以在程序中引入类似的诊断,通常不会影响现有程序。 |
12
1
让我把你已经提出的问题扩大一下。 以下是你在问题中的要点: 在C++中设置指针为NULL,并不是通用的好方法。有时:
但是,有 没有时间 当这是 坏的 !你会 不 通过显式地取消它引入更多的错误,您将不会 泄漏 记忆,你不会 导致未定义的行为 发生。 所以,如果有疑问,就取消它。 话虽如此,如果你觉得你必须显式地空一些指针,那么在我看来,这听起来好像你还没有足够地拆分一个方法,应该看看名为“提取方法”的重构方法,将该方法拆分成不同的部分。 |
13
1
对。 它所能做的唯一“危害”是在程序中引入低效率(不必要的存储操作),但在大多数情况下,与分配和释放内存块的成本相比,这种开销是微不足道的。 如果你不这么做,你 将 总有一天会有一些讨厌的指针错误。 我总是使用宏来删除:
(与数组类似,free(),释放句柄) 您还可以编写“self delete”方法来引用调用代码的指针,以便将调用代码的指针强制为空。例如,要删除许多对象的子树:
编辑 是的,这些技术确实违反了一些使用宏的规则(是的,这些天你可能会用模板得到同样的结果),但是通过多年的使用 从来没有 访问死区内存—调试可能遇到的问题中最糟糕、最困难、最耗时的问题之一。在多年的实践中,他们有效地消除了我介绍给他们的每个团队中的一类错误。 还有很多方法可以实现上面的功能——我只是想说明一个想法,如果人们删除了一个对象,就强迫他们空一个指针,而不是提供一种方法让他们释放不空调用方指针的内存。 当然,上面的例子只是迈向自动指针的一步。我没有建议,因为操作人员特别询问不使用自动指针的情况。 |
14
1
有时这是件好事,有时它毫无意义,可以掩盖错误 我可以看到两个问题: 简单的代码:
成为多线程环境中的for-liner:
唐·纽菲尔德的“最佳实践”并不总是适用的。在一个汽车项目中,即使在析构函数中,我们也必须将指针设置为0。我可以想象,在安全关键型软件中,这样的规则并不少见。跟随他们比试图说服他们容易(而且明智) 代码中使用的每个指针的团队/代码检查器,使该指针为空的行是多余的。 另一个危险是在使用代码的异常中依赖此技术:
在这样的代码中,要么产生资源泄漏并延迟问题,要么进程崩溃。 所以,这两个问题自然而然地出现在我的脑海中(赫伯·萨特肯定会告诉我更多),让我觉得“如何避免使用智能指针,如何安全地使用普通指针”这样的问题已经过时了。 |
15
0
总是有 Dangling Pointers 担心。 |
16
0
如果要在再次使用指针之前重新分配指针(取消对它的引用、将其传递给函数等),则使指针为空只是一个额外的操作。但是,如果您不确定在再次使用之前是否会重新分配它,那么将其设置为null是一个好主意。 正如许多人所说,使用智能指针当然要容易得多。 编辑:正如托马斯·马修斯在 this earlier answer ,如果在析构函数中删除了指针,则无需为其分配空值,因为该对象已被销毁,因此将不再使用该指针。 |
17
0
我可以想象,在删除指针后将其设置为null在以下情况下非常有用 合法的 在单个函数(或对象)中重用它的场景。否则就没有意义了——指针只要存在就需要指向有意义的东西——句点。 |
18
0
如果代码不属于应用程序中最关键的性能部分,请保持简单并使用共享的PTR:
它执行引用计数,并且是线程安全的。您可以在Tr1(STD::Tr1命名空间,γ包含和lt;内存& gt)中找到它,或者如果编译器不提供它,从Boost获取它。 |