Jer*_*dge 14 delphi validation pointers delphi-7
在另一个问题中,我发现Assigned()函数是相同的Pointer <> nil.一直是我的理解Assigned()是检测到这些悬空指针,但现在我已经知道它没有.悬空指针可能是在某一点上创建的,但此后已被释放且尚未分配nil.
如果Assigned()无法检测到悬空指针,那又可以呢?在尝试使用它之前,我想检查我的对象以确保它确实是一个有效的创建对象.我没有使用FreeAndNil尽可能多的推荐,因为我喜欢直接.我只是用SomeObject.Free.
访问违规是我最大的敌人 - 我尽我所能阻止他们出现.
afr*_*ier 14
如果您在范围内有一个对象变量,它可能是也可能不是有效的引用,FreeAndNil就是您应该使用的.那或修复你的代码,以便你的对象引用更严格地管理,所以它永远不是一个问题.
访问违规不应被视为敌人.他们是错误:他们意味着你犯了一个需要修复的错误.(或者你所依赖的某些代码中存在一个错误,但我经常发现我是那个搞砸了的人,特别是在处理RTL,VCL或Win32 API时.)
dth*_*rpe 13
有时可以检测指针指向的地址何时驻留在堆的释放内存块列表中的内存块中.但是,这需要将指针与堆的空闲列表中可能包含数千个块的每个块进行比较.因此,这可能是计算密集型操作,除非可能在严重的诊断模式下,否则您不希望经常这样做.
此技术仅在指针用于指向的内存块继续位于堆空闲列表中时起作用.当从堆中分配新对象时,释放的内存块很可能会从堆空闲列表中删除,并作为新的不同对象的主页重新进入活动状态.原始悬空指针仍指向同一地址,但生活在该地址的对象已更改.如果新分配的对象与现在释放的原始对象具有相同(或兼容)类型,则实际上无法知道指针是否作为对先前对象的引用.实际上,在这种非常特殊和罕见的情况下,悬空指针实际上可以很好地工作.唯一可观察到的问题可能是,如果有人注意到数据已经意外地从指针下面发生了变化.
除非您快速连续地一次又一次地分配和释放相同的对象类型,否则从该释放的内存块分配的新对象与原始内存块的类型相同可能很小.当原始对象和新对象的类型不同时,您有可能确定内容已从指针下方更改.但是,要做到这一点,您需要一种方法来了解指针所引用的原始对象的类型.在本机编译应用程序的许多情况下,指针变量本身的类型不会在运行时保留.就CPU而言,指针是指针 - 硬件对数据类型知之甚少.在严格的诊断模式中,可以想象您可以构建一个查找表来将每个指针变量与分配和分配给它的类型相关联,但这是一项艰巨的任务.
这就是为什么Assigned()不是指针有效的断言.它只是测试指针不是零.
为什么Borland创建Assigned()函数开始?进一步隐藏新手和偶尔程序员的指针.函数调用比指针操作更容易阅读和理解.
最重要的是,您不应该尝试检测代码中的悬空指针.如果要在释放指针后引用它们,请将指针设置为释放nil时.但最好的方法是不要在释放后引用指针.
那么,你如何在被释放后避免引用指针?有几个常见的习语会让你走得很远.
我强烈建议的一件事是避免if Assigned()在代码中编写测试,除非预期的行为是指针可能无法创建.您的代码将变得难以阅读,您也将忘记指针是否是预期的nil或是一个错误.
当然,我们都会犯错误并留下悬空指针.使用FreeAndNil是一种确保检测到悬空指针访问的廉价方法.更有效的方法是在完全调试模式下使用FastMM.我不能高度推荐这个.如果你没有使用这个很棒的工具,你应该尽快开始这样做.
如果你发现自己正在挣扎着晃来晃去的指针并且你发现很难解释为什么那么你可能需要重构代码以适应上面两个成语中的一个.
您可以绘制与数组索引错误并行的.我的建议是不要检查代码的索引有效性.而是使用范围检查,让工具完成工作并保持代码清洁.例外情况是输入来自程序外部,例如用户输入.
我的离别镜头:只有if Assigned在指针成为正常行为时才会写入nil.
使用提供调试支持的内存管理器(如FastMM),特别是使用给定的字节模式填充释放的内存块.然后,您可以取消引用指针以查看它是否指向以字节模式开头的内存块,或者如果它尝试通过悬空指针访问释放的内存块,则可以让代码运行通常也会引发AV.AV报告的内存地址通常与字节模式完全相同或接近.