如何检测指针是否被删除并安全删除?

时间:2013-03-31 15:09:11

标签: c++ pointers memory-management

C ++ 如何决定或知道指针是否在删除之前?

当我试图删除之前在代码的另一部分中删除的指针时,它抛出了一个无法处理的异常。

我想知道是否有办法检查或尝试删除指针?关于高级内存操作的任何参考。

我也想掌握指针的未处理异常,并且对受保护或访问的访问是违规的,......这种错误。

感谢那些提供一些知识和时间来帮助其他人并分享他们的好处的人


更新

许多现代c ++开发人员社区的重要建议是 - 使用智能指针或尝试避免使用原始指针。但是对于抛出安全性和保证没有内存(ISO_CPP_FAQ),当然如果你想避免使用智能指针的小开销[可能总是不明显但是它们有开销]你可以编写你的自定义方法来处理使用原始指针[type *] - 这不是一般的。 首选智能指针指向原始指针

在'Going Native 2013'中,给出了一个常见的建议 - 从不使用原始指针。

7 个答案:

答案 0 :(得分:26)

可以有三种解决方案。您可能希望根据您想要实现的努力/质量比选择一个:

优雅且最正确的解决方案:

使用 smart pointers ,您无需再次手动呼叫delete。这是克服此问题的最佳方法。它利用了RAII的原理,它非常适用于像C ++这样没有内置垃圾收集器的语言。

不太优雅但可行的解决方案:

删除后将指针指定给NULL。在delete指针上调用NULL是一项无操作,因此无需进行额外的NULL检查,但这可能隐藏一些问题而非制作它们可见。

不太优雅但更正确的解决方案:

通过让程序崩溃来解决所有多个delete问题。您也可以使用像valgrind这样的内存分析器程序,然后修复代码以避免所有这些问题。

答案 1 :(得分:5)

这是一个很好的问题,但在手动内存管理环境(如C / C ++及其堂兄弟)中工作的一个基本事实是,在事实之后没有好的方法来查看指针 / em>并询问它是否有效 - 一旦它变得无效,它就消失了,看着它很容易爆炸。你的工作是确保它永远不会删除或释放多次,并且在此之后永远不会被访问。

绝对要看智能指针,它们的发明是为了让程序员在这些情况下的生活变得更轻松。 (更传统的方法是要小心,不要搞砸,然后当你知道它被删除时,可能会给指针指定NULL,如Alok所说。)

答案 2 :(得分:3)

  

在C ++中如何判断或知道指针是否被删除?

语言标准没有提供任何合法的方法来确定任意指针是否有效。

有一种方法,但它是高度编译器/操作系统特定的。您可以挂钩到现有的内存管理器或用自己的内存管理器替换它,并提供专用的指针验证功能。但是,这可能不是很容易做到的。如果性能至关重要,你真的不想依赖这个功能。

答案 3 :(得分:2)

使用shared_ptr<>shared_array<>,记住shared_ptr<>只有在提供了适当的Deleter时才能用于管理分配给数组的内存,否则使用shared_array<>来管理数组

A* a_tab=new A[100];
boost::shared_ptr<A> a_tab_ok(a_tab,ArrayDeleter<A>()); 

//只有在

时才可以
template <typename T>
    class ArrayDeleter
    {
    public:
        void operator () (T* d) const
        {
            delete [] d; //will delete array!
        }
    };
提供

答案 4 :(得分:2)

指针不会告诉你任何事情。你的设计应该:如果 你正在使用动态分配,它通常是因为你的 应用程序要求对象具有特定的生命周期,所以 您知道何时正确删除该对象。如果对象是 您可以复制,或者具有与范围相对应的生命周期 不要(通常)动态分配它。

当然,在非常低级别的代码中有例外情况 你正在实现像std::vector这样的东西 使用某种动态分配,因为大小不是 在编译时已知。但这样的分配不应该逃脱; 低级别的责任是处理 记忆。

最后,缓冲区溢出,访问已删除的内存,以及 类似的是未定义的行为。一般来说,他们不 导致异常,而且没有通用的方法 处理它们。 (你可以通常安排在何时获得信号 这样的事情会发生,但你可以做的事情很少 信号处理程序,这对真的没什么帮助。)一般来说, 你想要的是程序崩溃,因为你不知道 它处于什么状态。在极少数情况下,这不是 在这种情况下,您必须依赖于实现定义 扩展,如果存在的话。如果使用/EHa进行编译 例如,使用VC ++的选项,通常会发生崩溃 将被转换为C ++异常。但这是一个VC ++ 扩展,你还是不知道整体的状态 程序何时发生。如果是因为你已经腐败了 自由空间竞技场,即使你可能做的也不多 你抓住了异常(而且很有可能你得到了 析构函数试图释放内存时的另一个例外 你放松堆栈。)

答案 5 :(得分:1)

智能指针是避免此类问题的更好选择(但在使用它们之前必须完全理解),但我想提一下与智能指针相关的性能限制,原因是它们通常使用原子操作,例如Win32中的InterlockedIncrement用于引用计数的API。这些函数明显慢于普通整数运算。我不确定你的情况下是否可以接受这么小的性能损失。

我通常做的是(因此我不必花费几天时间来调试讨厌的错误),我花了很多时间在设计和对象生命周期,然后移动实际编码,因为我删除内存我具体将指针设置为NULL,就我认为而言这是一个很好的做法。也许真正的解决方案是在继续之前花更多的时间来确定依赖关系和对象的生命周期!

答案 6 :(得分:1)

我知道这个帖子已经过时了。但如果其他人正在读这篇文章,他应该知道unique_ptr。 shared_ptr确实有开销。计数器存储在堆上。每次访问计数器时,都存在处理器高速缓存不匹配的风险。 unique_ptr比普通指针更有限但没有开销。我的建议是,当您不需要引用计数时,首选unique_ptr而不是shared_ptr。 另一个重要的通知是,unique_ptr适用于数组。 如果我没记错的话,对于自C ++ 17以来的shared_ptr也是如此。