C ++ Как работать с Invalid Pointers / Zero Pointers [duplicate]

Поскольку этот вопрос по-прежнему привлекает много пользователей из поиска Google (о таймере Android), я хотел бы вставить две мои монеты.

Прежде всего, Timer класс будет устаревшим в Java 9 (прочитайте принятый ответ) .

Предполагаемый способ official - использовать ScheduledThreadPoolExecutor , который является более эффективным и богатым функциональными возможностями, который может дополнительно планировать команды для запуска после определенной задержки или для выполнения периодически. Кроме того, это дает дополнительную гибкость и возможности ThreadPoolExecutor.

Вот пример использования простых функций.

  1. Создание службы-исполнителя:
    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
    
  2. Просто запланировать выполнение:
    final Future future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
    
  3. Теперь вы можете использовать future для отмены задачи или проверить, выполнено ли это, например:
    future.isDone();
    

Надеюсь, вы найдете это полезным для создания задач в Android.

Полный пример:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
    // Do something which will save world.
}

21
задан 2013Asker 19 June 2013 в 23:40
поделиться

5 ответов

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

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

33
ответ дан Kerrek SB 22 August 2018 в 23:53
поделиться

Если указатель установлен на 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)
4
ответ дан 0x499602D2 22 August 2018 в 23:53
поделиться

Как указано в других ответах, это невозможно с необработанным указателем формы 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 .

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

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

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

delete ptr;

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

9
ответ дан Mahesh 22 August 2018 в 23:53
поделиться
  • 1
    На самом деле, удаление не касается самого ptr, поэтому ptr тоже указывает на ту же память и разыгрывает ее также UB ... – Aconcagua 10 June 2016 в 05:36

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

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

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

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

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

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

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

5
ответ дан Mats Petersson 22 August 2018 в 23:53
поделиться
  • 1
    Если вы разыскиваете указатель на Т, который не указывает на объект типа T, поведение не определено, поэтому ваш вступительный оператор является ложным - он может не сбой. – Andrew Tomazos 20 June 2013 в 01:56
  • 2
    @ user1131467: Хорошо, я добавил заявление об этом. Мое главное было в том, что «если у вас плохой указатель (неверный, а не указатель на неправильный тип), трудно найти это без сбоев». – Mats Petersson 20 June 2013 в 08:53
  • 3
    Я не уверен, что первые несколько абзацев этого ответа добавят что-нибудь полезное в сообщение. Тем более, что вопрос заключается в том, указывает ли указатель на «действительный объект», а не на «действительную память». Недопустимый указатель часто является указателем, который был действителен до тех пор, пока пользователь не назовет delete, и в этом случае он может выглядеть так: правильно и, похоже, работают, но на самом деле возвращают мусор из зомби, который просто находится в пределах допустимого диапазона памяти вашего приложения. Итак, со всеми этими gotchas, возможно, лучше просто оставить его в «Нет». после чего следует избегать проверки правильности исходного указателя? – Agentlien 20 June 2013 в 09:49
  • 4
    @Agentlien Хорошо, я добавил «первое предложение». «Нет, вы не можете». – Mats Petersson 20 June 2013 в 09:58
  • 5
    На самом деле этого достаточно для улучшения моего вкуса. +1 – Agentlien 20 June 2013 в 10:04
Другие вопросы по тегам:

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