返回空值或抛出异常

returning null or throwing an exception?

本文关键字:抛出异常 空值 返回      更新时间:2023-10-16

我有以下类型:

typedef QPair < QTime , QTime > CalculatedTimeSlotRange;
typedef QList < CalculatedTimeSlotRange > CalculatedTimeSlotRangeList;
typedef QHash < quint8 , CalculatedTimeSlotRangeList > TimeSlotsTable;

我有一个像下面这样的函数:

const CalculatedTimeSlotRangeList* TimeSlots::getCalculatedTimeSlotRangeList(const quint8 id) const
{
    QHashIterator<quint8,CalculatedTimeSlotRangeList> it(mTimeSlotsTable);
    while (it.hasNext()) {
        it.next();
        if(it.key() == id) {
            return &it.value();
        }
    }
    return NULL;
}

,你可以看到我的函数返回一个NULL,如果它没有找到一个匹配id的键。这是正确的吗?或者如果键不存在,我应该抛出一个异常?对于这种情况,我应该如何抛出异常?

编辑:

在看到注释和答案后,我认为有必要指出,抛出异常或返回null并不重要。此事件暗示通过许多文件提供给程序的参数不正确。程序必须显示错误消息,并要求用户用正确的参数文件替换参数文件。那么哪种选择更好呢?异常指针或空指针,因为它们在上下文中的意思是一样的。如果问题和描述不能反映我的真实意图,请编辑。

问问你自己:如果你是使用这个函数的人,你希望它表现出哪种行为?这两种方法各有优缺点——如果抛出异常,则调用代码有责任了解这种可能性并在某个时候捕获异常,否则程序将abort(),这对用户来说与崩溃几乎是一样的。

另一方面,如果您的函数返回NULL,那么调用者有责任在继续之前检查返回值是否为空,否则他可能会因为空指针解引用而导致程序崩溃。此外,处理返回指向对象的指针的函数可能会因为对象所有权问题而令人困惑——调用者必须问自己,"我是否应该在使用完这个对象后删除它?"——如果这个问题的答案是错误的,将会导致崩溃或内存泄漏。

还有第三种您可能没有考虑过的选择:返回对虚拟对象的引用。使用该选项实现函数可能如下所示:

const CalculatedTimeSlotRangeList & TimeSlots::getCalculatedTimeSlotRangeList(const quint8 id) const
{
   QHashIterator<quint8,CalculatedTimeSlotRangeList> it(mTimeSlotsTable);
   while (it.hasNext()) {
       it.next();
       if(it.key() == id) {
           return it.value();
       }
   }
   static const CalculatedTimeSlotRangeList _dummyObject;  // note:  static to avoid dangling reference when returned!
   return _dummyObject;
}

我喜欢这种方法,因为现在用户不必担心检查NULL, ,他也不必担心正确处理异常。此函数将始终返回对有效的CalculatedTimeSlotRangeList的引用;在未找到的情况下,它将是一个空的/默认构造的;这(取决于您的特定用例)可能完全可以接受。

由于失败条件表明程序配置的致命条件,在您建议的选项中,我绝对建议抛出异常,因为这是一个真正的异常情况。

我认为invalid_argument在这里是有意义的,所以你会#include <stdexcept>,然后用throw std::invalid_argument("your error message about the bad configuration");代替return语句