如果找不到搜索结果,则返回“ NULL”对象


94

我对C ++相当陌生,因此在学习时,我倾向于使用许多Java风格进行设计。无论如何,在Java中,如果我有一个带有“搜索”方法的类,该类T将从Collection< T >与特定参数匹配的对象中返回一个对象,则将返回该对象,如果在集合中未找到该对象,则将返回null。然后在我的调用函数中,我只是检查if(tResult != null) { ... }

在C ++中,我发现null如果对象不存在,则无法返回值。我只想返回类型T的“指示器”,通知调用函数没有找到对象。我不想抛出异常,因为这并不是真正的例外情况。

这是我的代码现在的样子:

class Node {
    Attr& getAttribute(const string& attribute_name) const {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return NULL; // what should this be?
    }

private:
    vector<Attr> attributes;
}

我该如何更改它才能给出这种标记?


6
异常和NULL并不总是唯一的解决方案。您通常可以选择一个返回值,指示未找到:例如,如果没有元素匹配则std::find(first, last, value)返回last
卡斯卡贝尔

Answers:


70

在C ++中,引用不能为null。如果希望在没有找到任何内容的情况下返回null,则需要返回一个指针,而不是引用:

Attr *getAttribute(const string& attribute_name) const {
   //search collection
   //if found at i
        return &attributes[i];
   //if not found
        return nullptr;
}

否则,如果您坚持要通过引用返回,那么如果找不到该属性,则应该引发异常。

(顺便说一句,我有点担心您的方法正在const返回非const属性。出于哲学原因,我建议返回const Attr *。如果您还想修改此属性,则可以使用非const方法重载也返回非const属性。)


2
谢谢。顺便说一句,这是设计这种例程的一种公认方法吗?
10年

6
@aduric:是的。参考暗示结果必须存在。指针暗示结果可能不存在。
法案

7
只是好奇,我们现在返回nullptr而不是NULLc ++ 11吗?
频谱

1
是的,在C ++ 11和更高版本中,始终在NULL上使用nullptr。如果你需要与earliver版本向后兼容的话就不要
康拉德·琼斯

56

这里有几个可能的答案。您想返回可能存在的内容。以下是一些选项,从我最不喜欢到最喜欢:

  • 通过引用返回,并且无法通过异常找到信号。

    Attr& getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            throw no_such_attribute_error;
    }

找不到属性可能是执行的正常部分,因此不是很特殊。这种处理会很吵。无法返回空值,因为具有空引用是一种不确定的行为。

  • 指针返回

    Attr* getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return &attributes[i];
       //if not found
            return nullptr;
    }

很容易忘记检查getAttribute的结果是否为非NULL指针,并且是错误的简单来源。

  • 使用Boost.Optional

    boost::optional<Attr&> getAttribute(const string& attribute_name) const 
    {
       //search collection
       //if found at i
            return attributes[i];
       //if not found
            return boost::optional<Attr&>();
    }

boost :: optional表示此处到底发生了什么,并具有简单的方法来检查是否找到了这样的属性。


旁注:std :: optional最近在C ++ 17中被投票通过,因此在不久的将来这将是“标准”的事情。


+1我只会先提到boost :: optional,然后只简要提及其他选择。
Nemanja Trifunovic

是的,我在某处提到了boost :: optional,但是我认为这需要太多开销。如果使用它是解决此类问题的最佳方法,我将开始使用它。
aduric

boost::optional不需要太多的开销(没有动态分配),这就是为什么这么大的原因。将其与多态值一起使用需要包装引用或指针。
Matthieu M.

2
@MatthieuM。开销管理人员所指的可能不是性能,而是将外部库包含到项目中的成本。
Swoogan

我的答案的附录:请注意,正在进行将标准化为std组件的可选操作标准化的动静,很可能是C ++ 17。因此,值得了解此技术。
卡兹龙2014年

22

您可以轻松地创建一个表示NULL返回值的静态对象。

class Attr;
extern Attr AttrNull;

class Node { 
.... 

Attr& getAttribute(const string& attribute_name) const { 
   //search collection 
   //if found at i 
        return attributes[i]; 
   //if not found 
        return AttrNull; 
} 

bool IsNull(const Attr& test) const {
    return &test == &AttrNull;
}

 private: 
   vector<Attr> attributes; 
};

在源文件中的某处:

static Attr AttrNull;

NodeNull不应为Attr类型吗?
aduric


2

如您所知,您无法像使用Java(或C#)那样进行操作。这是另一个建议,您可以传入对象的引用作为参数并返回布尔值。如果在您的集合中找到结果,则可以将其分配给正在传递的引用,并返回'true',否则返回'false'。请考虑此代码。

typedef std::map<string, Operator> OPERATORS_MAP;

bool OperatorList::tryGetOperator(string token, Operator& op)
{
    bool val = false;

    OPERATORS_MAP::iterator it = m_operators.find(token);
    if (it != m_operators.end())
    {
        op = it->second;
        val = true;
    }
    return val;
}

上面的函数必须针对键“ token”找到操作符,如果找到返回真值的操作符,然后将值分配给参数Operator&op。

该例程的调用者代码如下所示

Operator opr;
if (OperatorList::tryGetOperator(strOperator, opr))
{
    //Do something here if true is returned.
}

1

在这里不能返回NULL的原因是,您已将返回类型声明为Attr&。尾随&使返回值成为“引用”,这基本上是指向现有对象的不为空的指针。如果您希望能够返回null,请更改Attr&Attr*


0

您无法返回,NULL因为函数的返回类型是对象reference而不是pointer


-3

您可以尝试以下方法:

return &Type();

6
尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。
NathanOliver 2015年

这可能返回对方法栈上的对象的无效引用,不是吗?
mpromonet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.