Вернуть объект NULL, если результат поиска не найден

Я довольно новичок в 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;
}

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

9 ответов

Решение

В 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 атрибут также.)

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

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

    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&>();
    }

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


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

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

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

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

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

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

Как вы поняли, что вы не можете сделать это так, как вы сделали в 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;
}

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

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

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

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

Есть еще один вариант, который можно было бы рассмотреть в этой ситуации — в зависимости от вашего дизайна. Вы можете вернуть значение, используя аргумент вашей функции, и заставить функцию возвращаться bool, например

      bool getAttribute(const string& attribute_name, Attr& returnAttr) const {
   //search collection
   //if found at i
        returnAttr = attributes[i];
        return true;
   //if not found
        return false;
}

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

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

return &Type();
Другие вопросы по тегам