C ++ Можно ли определить, указывает ли указатель на действительный объект?

21

Я изучаю C ++ и читаю C ++ Primer. Я хотел бы узнать ответ:

Учитывая указатель p , вы можете определить, указывает ли p на действительный объект? Если да, то как? Если нет, почему бы и нет?

Спасибо.

    
задан 2013Asker 20.06.2013 в 00:40
источник
  • Укажите «действительный». –  Doorknob 20.06.2013 в 00:41
  • Именно то, для чего нужны умные указатели. –  chris 20.06.2013 в 00:46
  • , если вы знаете, как работает основной менеджер памяти (как это делает его бухгалтерский учет), тогда вы могли бы это выяснить. Однако это будет очень специфично для платформы. Если вы сами управляете памятью, это не должно быть проблемой. Лучший курс действий по-прежнему должен придерживаться лучших практик (RAII, инкапсуляция). –  didierc 20.06.2013 в 01:48
  • @chris - это то, для чего нужны умные указатели. Но GIGO все еще применяется; вы всегда можете создать интеллектуальный указатель, который содержит плохой указатель. –  Pete Becker 20.06.2013 в 13:18
  • @PeteBecker, ну да, но если вы используете их правильно и тщательно для управления своей памятью, у вас не должно быть этой проблемы. Что касается вещей без динамического распределения, они теряют немного ценность в этом смысле. –  chris 20.06.2013 в 17:39
Показать остальные комментарии

5 ответов

32

Нет, вы не можете. Зачем? Потому что было бы дорого поддерживать метаданные о том, что представляет собой действительный указатель, а что нет, а на C ++ вы не платите за то, что не хотите.

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

    
ответ дан Kerrek SB 20.06.2013 в 00:45
источник
8

Невозможно. Подумайте об этом сценарии.

int *ptr = new int(10);
int *ptrDup = ptr;

delete ptr;

Но ptrDup все еще указывает на ячейку памяти, указанную ptr , которая больше не существует. Таким образом, отсрочка ptrDup приводит к неопределенному поведению. Но есть подсчет ссылок, который является совершенно другой концепцией.

    
ответ дан Mahesh 20.06.2013 в 00:45
источник
  • На самом деле, удаление не касается самого ptr, поэтому ptr тоже указывает на ту же память и разыгрывает ее также UB ... –  Aconcagua 10.06.2016 в 07:36
5

Невозможно увидеть, является ли указатель «действительным» во всех его значениях.

Конечно, вы можете попытаться разыменовать указатель ( *ptr = x; или x = *ptr ). Если ваш код не сбой, указатель указывает на действительную память. Если он упал, очевидно, указатель не годится. К сожалению, этот подход немного похож на проверку того, загружена ли пушка, выстрелив в голову - что не самое умное ... К сожалению, с указателями нет «проверьте камеру, чтобы увидеть, загружена ли она», поэтому нет реального хорошего способа выяснить, является ли указатель действительным, кроме «если он не вызывает аппаратную ошибку, он действителен».

Обратите внимание, что это только на самом деле скажет вам, что «указатель указывает на некоторую память, к которой вы можете получить доступ» в большинстве случаев. Это НЕ означает, что указатель «правильный для того, что вы хотите» (например, указывает на правильный тип). И это НЕКОТОРНО не скажет вам, указывает ли указатель на «устаревшие данные» (то есть, когда указатель WAS действителен, но теперь он используется для чего-то другого).

К сожалению, с 2 32 или 2 64 [фактически 2 48 ] возможно действительными адресами памяти в современной системе, почти невозможно знать, какие адреса действительны, а какие нет. Даже внутри операционной системы, как показывает ОС, если она может записать в память, которую вы попросили написать, это «попытаться написать ее, посмотреть, что произойдет». Для ОС это работает отлично, потому что это может быть осторожным, «это может пойти не так, и если это произойдет, я продолжу там в коде восстановления ошибок». ОС должна справиться с этим, потому что она должна принять, а) что программисты совершают ошибки, и б) что некоторые люди на самом деле пишу вредоносный код для TRY, чтобы разорвать ОС.

Способ для приложения «удостовериться, что указатели действительны» - это то, что программист пишет код, который ОСТОРОЖНО, о том, что он хранит в указателях, как он освобождает эти указатели и использует только указатели, в которых хранятся действительные значения. Вы не должны заканчивать «необходимость проверки правильности указателя» - тогда вы «делаете это неправильно».

(Когда вы некоторое время работаете с системой и читаете значения указателя в отладчике, вы через некоторое время узнаете «хорошие» и «плохие» указатели, но это только потому, что вы узнаете, что, как правило, хороший указатель а плохой указатель выглядит так: писать код, чтобы распознать его, почти невозможно - особенно если система выделяет много памяти, поэтому использует большую часть доступного пространства.)

Конечно, в C ++ существуют интеллектуальные указатели, векторы и различные другие инструменты, которые означают много времени, когда вам даже не нужно беспокоиться о указателях. Но понимание того, как использовать указатели и как работают указатели, по-прежнему хорошо.     

ответ дан Mats Petersson 20.06.2013 в 01:06
источник
  • Если вы отменили указатель-to-T, который не указывает на объект типа T, поведение не определено, поэтому ваш вступительный оператор является ложным - он может не сбой. –  Andrew Tomazos 20.06.2013 в 02:56
  • @ user1131467: Хорошо, я добавил заявление об этом. Мое главное было в том, что «если у вас плохой указатель (неверный, а не указатель на неправильный тип), трудно найти это без сбоев». –  Mats Petersson 20.06.2013 в 09:53
  • Я не уверен, что первые несколько абзацев этого ответа добавят что-нибудь полезное в сообщение. Тем более, что вопрос заключается в том, указывает ли указатель на «действительный объект», а не на «действительную память». Недопустимый указатель часто является указателем, который был действителен до тех пор, пока пользователь не назовет delete, и в этом случае он может «выглядеть» корректно и, похоже, работать, но на самом деле возвращать мусор, который просто находится в пределах допустимого диапазона памяти вашего приложения. Итак, со всеми этими ошибками, может быть, лучше просто оставить его в «Нет», а затем как избежать проверки правильности исходного указателя? –  Agentlien 20.06.2013 в 10:49
  • @Agentlien Хорошо, я добавил «первое предложение», чтобы сказать «Нет, вы не можете». –  Mats Petersson 20.06.2013 в 10:58
  • Это на самом деле достаточно для улучшения моего вкуса. +1 –  Agentlien 20.06.2013 в 11:04
4

Если указатель установлен в nullptr , это означает, что ему не был дан объект, на который он указывает, и вместо этого ему присваивается значение по умолчанию. Возможно, что указателю можно присвоить not nullptr и , но не назначить действительный объект, но в этом случае было бы невозможно определить что. Например:

С nullptr :

int *ptr = nullptr;

// check if pointer is unassigned to an object
if (ptr == nullptr) ptr = new int{0};

Без nullptr :

int *ptr;

// using ptr while uninitialized is Undefined Behavior!
if (ptr != &some_object)
    
ответ дан 0x499602D2 20.06.2013 в 00:47
источник
1

Как указано в других ответах, это невозможно с необработанным указателем формы SomeObject* somePointer . Однако c++11 представила новый набор управления динамической памятью и новых интеллектуальных указателей . Используя интеллектуальный указатель, вы можете определить, доступен ли ресурс. Например, в следующем:

std::weak_ptr<int> w; // Our pointer to a resource.
{
    std::shared_pointer<int> s = std::make_shared<int>(5); // The resource.

    w = s;       // We can set the weak pointer to the shared pointer.

    auto s2 = w; // Here we can promote the weak pointer to a shared  pointer to control 
                 // the resource.

    *s2 = 6;     // Here we can use the resource.

}                // Here the resource is destroyed.

auto s2 = w;     // Here we will fail to get the resource because it has been destroyed. We
                 // have successfully used smart pointers to detect if the resource exists.

Подробнее о std :: shared_ptr и std::weak_ptr для получения дополнительных примеров. До c++11 эквивалентные типы интеллектуальных указателей доступны в boost .     

ответ дан Fantastic Mr Fox 07.02.2018 в 00:58
источник
  • Умные указатели (намного) лучше на C ++ 11, но они были введены задолго до ... –  Ben Voigt 07.02.2018 в 01:22
  • @BenVoigt Я добавлю слово new, но я действительно не хочу говорить об этом auto_ptr, потому что мне нужна страница, почему бы не использовать ее. Я добавлю также примечание об усилении. –  Fantastic Mr Fox 07.02.2018 в 01:48