Проверка указателя на указатель в C++

Я пытаюсь написать функцию, которая получает указатель, использует его, а затем указывает на новый объект. Для этого я использую ptr-to-ptr. Вот как я проверяю ptr-to-ptr, полученный моей функцией:

void modifyPtr(Obj ** ptrToPtr)
{
    if (*ptrToPtr == nullptr)
    {
        return;
    }
    else
    {
        // Do everything else!
    }
}

Пока писал это, я подумал: а что, если клиент передаст моей функции следующее?

Obj ** ptrToPtr = nullptr;
modifyPtr(ptrToPtr);

В этом случае моя проверка будет опасной, потому что я буду разыменовывать nullptr. Итак, должен ли я добавить дополнительный шаг проверки?

void modifyPtr(Obj ** ptrToPtr)
{
    if (ptrToPtr == nullptr)
    {
        return;
    }
    else if (*ptrToPtr == nullptr)
    {
        return;
    }
    else
    {
        // Do everything else!
    }
}

Я никогда раньше не видел такой проверки, поэтому и сомневаюсь.

Имейте в виду, что я знаю, что в C++ следует избегать использования необработанных указателей. Я работаю со старым кодом и нахожу эту проблему интересной.


person user3266738    schedule 10.01.2018    source источник
comment
Ваша первая проверка неверна, потому что вы разыменовываете ptrToPtr перед проверкой, является ли оно нулевым. Вам, вероятно, не нужно проверять разыменованный указатель на нуль, поскольку вы все равно собираетесь его изменить (если только вам не нужно что-то делать со старым объектом). Но лучше использовать ссылки вместо двойных указателей, например: void modifyPtr(Obj* &Ptr), тогда вызывающая сторона не сможет передать нулевую ссылку   -  person Remy Lebeau    schedule 10.01.2018
comment
@RemyLebeau, вы могли бы буквально просто скопировать + вставить этот комментарий в качестве ответа, и это был бы хороший ответ!   -  person Tas    schedule 10.01.2018
comment
Несвязанный: нет ничего плохого в том, чтобы часто использовать необработанные указатели. Владение необработанными указателями — это то, чего вы хотите избежать. Вы хотите автоматизировать управление, чтобы было труднее пропустить очистку и т. д., но после этого передача необработанного указателя может быть правильным решением. Но по-прежнему предпочитаю передавать ссылки, где это возможно.   -  person user4581301    schedule 10.01.2018
comment
Да @RemyLebeau, вы должны опубликовать это как ответ, и я приму его. Это отличный ответ! Спасибо :-)   -  person user3266738    schedule 10.01.2018
comment
@RemyLebeau недостаточно изменить функцию, чтобы принять ссылку. Вы все еще можете сделать Obj ** ptrToPtr = nullptr; modifyPtr(*ptrToPtr); и получить хорошее неопределенное поведение.   -  person Mark Ransom    schedule 10.01.2018
comment
@MarkRansom: да, но кто в здравом уме мог бы это сделать? Когда вы видите что-то вроде Obj* &ptr, совершенно очевидно, что функция ожидает, что вызывающая сторона вместо этого сделает что-то вроде Obj *ptr = ...; modifyPtr(ptr);.   -  person Remy Lebeau    schedule 10.01.2018
comment
Нет особого смысла добавлять операторы else после выполнения return. Ты либо возвращаешься, либо нет.   -  person Sid S    schedule 10.01.2018
comment
Лучше передавать интеллектуальный указатель по ссылке, например: std::unique_ptr.   -  person Galik    schedule 10.01.2018
comment
@Galik, если вы делаете это, вы ограничиваете себя в использовании любого другого указателя, например. std::shared_ptr.   -  person Mark Ransom    schedule 10.01.2018
comment
@MarkRansom Действительно, вы правы. Но право собственности должно быть четко определено, поэтому ограничение того, кто может владеть объектом, должно быть преимуществом, а не проблемой. И, в конце концов, альтернатива — вообще не использовать умные указатели.   -  person Galik    schedule 10.01.2018
comment
@Galik владение указателем не должно беспокоить функцию, если только она не меняет владельца. В данном конкретном примере это может быть уместно, но я бы не считал это общим правилом.   -  person Mark Ransom    schedule 10.01.2018


Ответы (4)


Ваша первая проверка неверна, потому что вы разыменовываете ptrToPtr перед проверкой, является ли оно нулевым.

Вам, вероятно, не нужно проверять разыменованный указатель на нуль, поскольку вы все равно собираетесь его изменить (если только вам не нужно что-то делать со старым объектом).

Однако вы должны предпочесть использовать ссылки вместо двойных указателей, например:

void modifyPtr(Obj* &Ptr)

Тогда вызывающая сторона не может передать нулевую ссылку (без уродливых хаков).

person Remy Lebeau    schedule 10.01.2018
comment
Это не уродливый взлом, просто несчастный случай, который должен произойти. Obj **ptrToPtr = GetPP(); Obj** GetPP() { if (some_condition) return nullptr; ... }. Однажды я обжегся этим в реальном коде, поэтому теперь я особенно чувствителен к этому. Если существует какая-либо вероятность наличия нулевого указателя, не пытайтесь преобразовать его в ссылку и думайте, что вы в безопасности. См. stackoverflow.com/questions/57483/ для моего полного описания. - person Mark Ransom; 10.01.2018

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

person zneak    schedule 10.01.2018

// использовать ссылку.

void modifyPtr(Obj *& ptrToPtr)
{
    if (ptrToPtr == nullptr)
    {
        return;
    }
    else
    {
        // Do everything else!
    }
}

Obj * ptrToPtr = nullptr;
modifyPtr(ptrToPtr);
person love apple    schedule 10.01.2018

В вашем первом, если вы ничего не разыменовываете. Вы просто проверяете, является ли переданный указатель нулевым или нет. Так что вам не о чем беспокоиться. Просто удалите *, который я не заметил на своем мобильном телефоне

person 0___________    schedule 10.01.2018