Вернуть объект NULL, если результат поиска не найден - PullRequest
88 голосов
/ 14 апреля 2010

Я довольно новичок в C ++, поэтому я склоняюсь к разработке с большим количеством Java-измов во время обучения. В любом случае, в Java, если бы у меня был класс с методом 'search', который возвращал бы объект 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;
}

Как я могу изменить это, чтобы я мог дать такой маркер?

Ответы [ 8 ]

61 голосов
/ 14 апреля 2010

В C ++ ссылки не могут быть нулевыми. Если вы хотите при желании вернуть 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 атрибут.)

52 голосов
/ 14 апреля 2010

Здесь есть несколько возможных ответов. Вы хотите вернуть то, что может существовать. Вот несколько вариантов, от моего наименее предпочтительного до наиболее предпочтительного:

  • Возврат по ссылке, и сигнал не может быть найден по исключению.

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

Повышение :: опционально точно указывает, что здесь происходит, и имеет простые методы проверки, был ли найден такой атрибут.


Примечание: недавно в C ++ 17 проголосовал std :: option, так что в ближайшем будущем это станет "стандартной" вещью.

22 голосов
/ 14 апреля 2010

Вы можете легко создать статический объект, который представляет 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;
3 голосов
/ 14 апреля 2010

Если вы хотите получить NULL возвращаемое значение, вам нужно использовать указатели вместо ссылок.

Ссылки сами по себе не могут быть NULL.

(Примечание к будущим комментариям: да, адрес ссылки может быть НЕДЕЙСТВИТЕЛЕН, если вы действительно действительно пытаетесь это сделать).

См. Мой ответ здесь для списка различий между ссылками и указателями .

2 голосов
/ 20 февраля 2016

Как вы поняли, что вы не можете сделать это так, как вы делали в Java (или C #). Вот еще одно предложение, вы можете передать ссылку на объект в качестве аргумента и вернуть значение bool. Если результат найден в вашей коллекции, вы можете присвоить его передаваемой ссылке и вернуть «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;
}

Приведенная выше функция должна найти оператора по ключу 'токен', если он находит тот, который возвращает true, и присвоить значение параметру Operator & op.

Код вызывающего абонента для этой процедуры выглядит следующим образом

Operator opr;
if (OperatorList::tryGetOperator(strOperator, opr))
{
    //Do something here if true is returned.
}
1 голос
/ 14 апреля 2010

Причина, по которой вы не можете вернуть NULL, заключается в том, что вы объявили тип возврата как Attr&. Трейлинг & делает возвращаемое значение «ссылкой», которая в основном является указателем с гарантированным, не равным нулю, указателем на существующий объект. Если вы хотите иметь возможность возвращать ноль, измените Attr& на Attr*.

0 голосов
/ 15 декабря 2015

Вы можете попробовать это:

return &Type();
0 голосов
/ 14 апреля 2010

Невозможно вернуть NULL, поскольку возвращаемым типом функции является объект reference, а не pointer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...