Что такое не указатель эквивалент NULL?

Извиняюсь за неправильную терминологию.

У меня есть фрагмент кода, который возвращает нулевой указатель, если запись не существует:

ObjectType * MyClass::FindObjectType( const char * objectTypeName )
{
    if ( objectTypeMap.find( objectTypeName ) == objectTypeMap.end() )
    {
        Msg( "\n[C++ ERROR] No object type: %s", objectTypeName );
        return NULL;
    }
    else
        return &objectTypeMap[ objectTypeName ];
}

Я хочу сделать то же самое, но на этот раз возвращать объект, а не только указатель. Следующий код не дает мне никаких ошибок компилятора (что меня удивляет):

ObjectType MyClass::FindObjectType( const char * objectTypeName )
{
    if ( objectTypeMap.find( objectTypeName ) == objectTypeMap.end() )
    {
        Msg( "\n[C++ ERROR] No object type: %s", objectTypeName );
    }
    else
        return objectTypeMap[ objectTypeName ];
}

С помощью указателя я могу проверить, была ли запись найдена следующим образом:

if ( FindObjectType( objectType ) == NULL )
    //Do something

Как выполнить эквивалентную проверку возвращаемого объекта?

10 голосов | спросил Phlox Midas 7 J0000006Europe/Moscow 2012, 14:12:36

2 ответа


0

Для объектов не существует эквивалента на уровне языка.

Один из вариантов - создать объект «страж», который гарантированно сравнивает неравные значения с любым «реальным» объектом, и вернуть это:

class ObjectType {
public:
    static const ObjectType null;

    bool operator==(const ObjectType &rhs) const { /* need an appropriate comparison test */ }

    ...
};

ObjectType ObjectType::null(/* something unique */);


...

ObjectType foo(const char *objectTypeName) {
    if (cond) {
        return objectTypeMap[objectTypeName];
    } else {
        return ObjectType::null;
    }
}


...

if (foo(objectType) == ObjectType::null) {
    std::cout << "Returned the null object\n";
}
ответил Oliver Charlesworth 7 J0000006Europe/Moscow 2012, 14:13:51
0

Следующий код не выдает ошибку, потому что стандарт очень консервативный.

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

Однако в стандарте говорится, что если функция завершается нормально (без исключения) без возврата значения, то вызывается Неопределенное поведение (т. е. может произойти все что угодно, скорее всего вылет). Таким образом, большинство компиляторов имеют предупреждение для такой ситуации, для gcc и Clang вы можете использовать -Wreturn.


Теперь принцип недействительности или дозорных значений не нов, и нулевой указатель - это просто одно воплощение (среди многих).

Если для вашего объекта нет смысла обнуляться (это редко бывает, но может быть целесообразно), тогда у вас есть 2 варианта:

  • throw исключение, сигнализирующее об ошибке
  • возвращает класс-оболочку (например, boost::optional<ObjectType>), который может быть нулевым

В этом состоянии, поскольку ожидается, что Find ничего не найдет, я бы посоветовал последнее вообще.

Использование простое:

boost::optional<ObjectType> MyClass::FindObjectType(char const* objectTypeName )
{
    if ( objectTypeMap.find( objectTypeName ) == objectTypeMap.end() ) {
        // do not print anything, it is up to the caller to decide what to do
        return boost::none;
    }

    return objectTypeMap[ objectTypeName ];
}

А потом звонящий пишет:

int main(int argc, char* argv[]) {
    if (boost::optional<ObjectType> o = MyClass::FindObject(argv[1])) {
        o->foo();

        return 0;
    }

    Msg( "\n[C++ ERROR] No object type: %s", argv[1]);
    return 1;
}
ответил Matthieu M. 7 J0000006Europe/Moscow 2012, 15:49:50

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132