在大型c ++代码库中避免空指针异常

时间:2009-07-25 00:54:05

标签: c++ null nullpointerexception

我继承了一个大的c ++代码库,我有一个任务是避免代码库中可能发生的任何空指针异常。是否有可用的静态分析工具,我在想,你已经成功使用了。

你还有什么其他的东西?

6 个答案:

答案 0 :(得分:5)

您可以从消除NULL源开始:

更改

if (error) {
    return NULL;
}

if (error) {
    return DefaultObject; // Ex: an empty vector
}

如果返回的默认对象不适用且您的代码库已经使用了异常,请执行

if (error) {
    throw BadThingHappenedException;
}

然后,在适当的地方添加处理。

如果您正在使用遗留代码,则可以创建一些包装函数/类:

ResultType *new_function() {
    ResultType *result = legacy_function();
    if (result) {
        return result;
    } else {
        throw BadThingHappenedException;
    }
}

新功能应该开始使用新功能并进行适当的异常处理。

我知道有些程序员不会得到例外,包括像Joel这样的聪明人。但是,通过返回NULL最终发生的事情是,这个NULL会像疯了一样传递,因为每个人都会认为处理它并静默返回并不是他们的事。某些函数可能会返回错误代码,这很好,但是调用者通常最终会返回NULL-another-NULL以响应错误。然后,无论函数多么微不足道,您都会在每个函数中看到很多NULL检查。并且,只需要一个不检查NULL以使程序崩溃的地方。例外情况迫使您仔细考虑错误并确定应该在何处以及如何处理。

您似乎只是在寻找简单的解决方案,例如静态分析工具(您应该经常使用)。更改引用指针也是一个很好的解决方案。但是,C ++具有RAII的优点,它无需在任何地方“尝试{}”,所以我认为值得您认真考虑。

答案 1 :(得分:2)

如果您主要维护代码库,那么您可以做的最低工作量和最高回报之一就是开始重构您的指针reference counted pointers

我还会查看Purify之类的内容,它会检测代码以检测内存损坏。

答案 2 :(得分:2)

首先,作为技术问题,C ++没有NULL指针异常。取消引用NULL指针具有未定义的行为,并且在大多数系统上导致程序突然终止(“崩溃”)。

至于工具,我也推荐这个问题:

Are C++ static code analyis tools worth it?

特别是关于NULL指针解除引用,请考虑NULL指针解除引用有三个主要元素:

  1. 引入NULL指针。
  2. 该指针在程序中其他位置的流程。
  3. 指针的解除引用。
  4. 静态分析工具的难点部分当然是步骤2,工具的区别在于它们可以准确地(即,没有太多误报)轨道的复杂路径。查看一些您想要捕获的错误的具体示例可能会有用,以便更好地建议哪种工具最有效。

    免责声明:我为Coverity工作。

答案 3 :(得分:2)

如果您不想更改任何代码,则必须使用某些工具(请参阅其他答案)。但是对于问题的一个特殊部分(你将一个指针放在一个函数中使用它),你可以使用一个很好的小Makro-Definition来找到一些小Buggers: (在发布模式下没有时间开销,并为代码添加了可见条件)

    #ifdef  NDEBUG

    #define NotNull(X) X

    #else // in Debug-Mode

    template<typename T> class NotNull;

    template<typename T> // template specialization only for pointer-types
    class NotNull<T*> {
    public:
        NotNull(T* object)
        : _object(object) {
            assert(object);
        }

        operator T*() const {
            return _object;
        }

        T* operator->() const {
            return _object;
        }
    private:
        T *_object;
    };

    #define NotNull(X) NotNull<X>

    #endif // in Debug-Mode

您只需更改此功能:

void increase(int* counter)  
{ .. } 

到这个

void increase(NotNull(int*) counter)
{ .. }  

p.s:首先找到HERE,可以进一步调整

答案 4 :(得分:1)

答案 5 :(得分:1)

一个附带问题,是避免这些的目的,因为他们不希望客户看到崩溃?在许多情况下,空指针是应该立即处理的意外情况,但通常它们会像烫手山芋一样通过系统传递。

我曾经在一个代码库上工作,习惯是在进入函数时,首先检查是否有任何空指针,如果是,则返回。这个问题是当工具没有崩溃时,它最终会无声地生成坏数据。并且尝试调试这些问题很困难,因为在结果变得无法容忍或最终不得不表现出来之前,可能已经有很长时间通过许多函数传递了非法的空指针。

理想情况下,您至少在开发期间需要正确的断言,因此请考虑使用宏来隐藏或重新定义生成构建的断言