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

Я новичок в С++, поэтому я стараюсь разрабатывать множество Java-измов во время обучения. В любом случае, на Java, если бы у меня был класс с методом поиска, который возвращал бы объект T из Collection< T >, который соответствовал конкретному параметру, я бы вернул этот объект и если объект не был найден в коллекции, Я вернусь null. Тогда в моей вызывающей функции я просто проверил бы if(tResult != null) { ... }

В С++ я обнаруживаю, что я не могу вернуть значение 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;
}

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

Ответ 1

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

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

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

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

Вероятно, что поиск атрибутов не является нормальной частью исполнения и, следовательно, не очень исключителен. Обработка этого была бы шумной. Нулевое значение не может быть возвращено, поскольку его поведение undefined имеет нулевые ссылки.

  • Возврат указателем

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

A boost:: optional означает то, что здесь происходит, и имеет простые методы для проверки того, был ли найден такой атрибут.


Боковое примечание: std:: optional недавно был проголосован за С++ 17, так что это будет "стандартная" вещь в ближайшем будущем.

Ответ 3

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

Ответ 4

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

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

(Примечание к плакатам будущего комментария: Да, вы можете указать адрес ссылки NULL, если вы действительно действительно пытаетесь).

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

Вы можете попробовать следующее:

return &Type();