LINUX.ORG.RU

Qt и проверка указателей на 0

 ,


0

2

Практически во всех примерах с использованием Qt (да и не только, вообщем-то) после создания указателя с помощью new сразу идёт его использование безо всякой проверки на 0. С одной стороны это не создаёт лишних строк для человека, который смотрит этот код в качестве примера, и даёт общую картину как использовать код. Но меня настораживает то, что я вижу такой код во многих программах. Т.е. никаких проверок на 0. Получили указатель - и вперёд. Я не помню, где я читал, но мне встречалась такая информация, что, якобы, если new возвращает 0, то уже особо и нет смысла дальше что-то делать, т.к. программа будет уже работать некорректно из-за нехватки памяти. Вот так вот кардинально получается: либо всё, либо уже ничего (программа в таком случае обычно вылетает). Я размышлял над этим несколько недель. В итоге в своих программах я обязательно проверяю каждый указатель. Хоть и в недрах Qt я нахожу, что там часто не проверяется, но считаю, что если и будет кто-то виноват в разыменовании нуля, то хотя бы пусть это буду не я.

Возникает вопрос: как же всё-таки правильно поступать - проверять или уже не заморачиваться с каждым указателем? Есть подозрение, что отсутствие подобных проверок - это просто быдлокод. Но хочется понять, как же правильно.


Qt тут не при чем. Если new обломается, получишь эксепшн.

panter_dsd ★★★★ ()
Последнее исправление: panter_dsd (всего исправлений: 1)

new по-умолчанию не возвращает 0. Вместо этого он кидает bad_alloc. Поэтому проверять тут нечего.

Если ты хочешь, чтобы new возвращал тебе 0, нужно его об этом попросить: http://www.cplusplus.com/reference/new/nothrow/

yoghurt ★★★★★ ()

Кагбе положено ставить собственный обработчик исключения от new с помощью set_new_handler(), а не полагаться на возврат 0. (Что-то я сходу в стандарте вообще не нашёл, что new обязан его возвращать в таких случаях.)

alegz ★★ ()
Ответ на: комментарий от yoghurt

Вот это поворот... Спасибо, не знал. Век живи, век учись.

RomanU ()

На nullptr нужно проверять после всяких кастов.

panter_dsd ★★★★ ()
Ответ на: комментарий от panter_dsd

Ну касты - это понятно, тут я согласен. Речь шла именно о new.

RomanU ()
Ответ на: комментарий от yoghurt

В зависимости от версии компилятора. Он может и 0 вернуть а может и std::bad_alloc

energyclab ()
Ответ на: комментарий от energyclab

Это уже интереснее. А есть пример такого компилятора, который вернёт 0 для данного случая?

RomanU ()

Есть доки и примеры по QT. Думаю, что правильно делать так, как в них указано (ну хотя в 99% случаев). А потом, пойди попробуй съешь всю памать приложения. В x86_64 такое вообще тяжко сделать.

energyclab ()
Ответ на: комментарий от RomanU

Версию точно не назову, но точно помню, что когда читал книгу Дейтлов, там на это явно делали акцент, и показали, что самым правильным решением ялвляется код типа:

...
try {
   char *p = new char[10];
   if(!p) {
      throw std::bad_alloc();
   }
   ...
}
catch(std::bad_alloc &e) {
  ...
}

energyclab ()
Ответ на: комментарий от energyclab

QT != Qt

В зависимости от версии компилятора. Он может и 0 вернуть а может и std::bad_alloc

Где пруф?

panter_dsd ★★★★ ()
Ответ на: комментарий от energyclab

И так на каждое создание объекта? Представляю, во что превратится код...

panter_dsd ★★★★ ()
Ответ на: комментарий от panter_dsd

Ну не отпустил я кнопку shift когда писал «QT», но все-равно яснож о чем речь идет...

В зависимости от версии компилятора. Он может и 0 вернуть а может и std::bad_alloc

Это не было привязано к Qt

energyclab ()
Ответ на: комментарий от energyclab

В зависимости от версии компилятора. Он может и 0 вернуть а может и std::bad_alloc

4.2 (рахитские компиляторы не в счет).

18.6.1.1

Single-object forms

void* operator new(std::size_t size);

Required behavior: Return a non-null pointer to suitably aligned storage (3.7.4), or else throw a bad_alloc exception. This requirement is binding on a replacement version of this function.

Pavval ★★★★★ ()
Ответ на: комментарий от energyclab

Ага, спасибо. Вот что нашёл, например: http://qt-project.org/doc/qt-4.8/symbianexceptionsafety.html

«When writing Qt code, new will normally throw a std::bad_alloc if the allocation fails. However this may not happen if the object being created has its own operator new.»

Получается, что оператор new в Qt генерирует исключение при отсутствии памяти. Тогда всё становится понятно. Благодарю всех ответивших!

P.S. Вот, кстати, по ключевым словам нашёл «коллегу» по вопросу: http://stackoverflow.com/questions/1308052/policy-with-catching-stdbad-alloc

RomanU ()
Ответ на: комментарий от panter_dsd

ну это же учебное пособие... А так, я уже сказал, чтобы в реальной программе получить bad_alloc нужно постараться хорошо... ps. Я для себя давно написал простой менеджер памяти, котрый следит за веделенной и освобожденной памятью... и, явно, new не использую нигде акромя Qt проектов

energyclab ()
Ответ на: комментарий от Pavval

4.2 (рахитские компиляторы не в счет).

Я просто упомянул, что такое было в книге

energyclab ()

Т.е. никаких проверок на 0.

Это потому, что new должен бросать исключение. Проверка на 0 не нужна в этом случае.

но мне встречалась такая информация, что, якобы, если new возвращает 0

Да, так было сто лет назад. Теперь исключение.

andreyu ★★★★★ ()
Ответ на: комментарий от yoghurt

new по-умолчанию не возвращает 0. Вместо этого он кидает bad_alloc. Поэтому проверять тут нечего.

Во дела, я реально не знал. Для меня если не выделилось - значит будет 0, так думал...

Но так как я пишу на Qt - я никогда не выделяю память сам, в моих C++ программах давно уже нет new и delete.

I-Love-Microsoft ★★★★★ ()

В Linux у твоего процесса несоизмеримо больше шансов быть убитым OOM-киллером, чем получить 0 (или исключение) при аллокации

annulen ★★★★★ ()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Но так как я пишу на Qt - я никогда не выделяю память сам, в моих C++ программах давно уже нет new и delete.

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

annulen ★★★★★ ()
Ответ на: комментарий от annulen

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

Создается QByteArray (resize) или QImage (там сразу можно задать разрешение и формат), я получаю указатель, записываю что надо, и всё - эта память, с моими данными - под властью Qt и когда надо - очистится автоматом.

Про такие вещи был вопрос ко мне?

Всё, понял. Ты про QList<shit_class*> - да? Там у меня всё же new и delete... Но стараюсь QList/QVector<shit_class> crap, а указатель - &crap. Стремлюсь не управлять памятью сам, но указателями пользуюсь.

I-Love-Microsoft ★★★★★ ()
Последнее исправление: I-Love-Microsoft (всего исправлений: 3)
Ответ на: комментарий от I-Love-Microsoft

Ты про QList<shit_class*> - да?

Именно

Но стараюсь QList/QVector<shit_class> crap

Не всегда применимо, особенно если не хочется лишних операций копирования

annulen ★★★★★ ()
Ответ на: комментарий от energyclab

В зависимости от версии компилятора. Он может и 0 вернуть а может и std::bad_alloc

Не может. Поведение чётко предписано стандартом.

slovazap ★★★★★ ()
Ответ на: комментарий от energyclab

Сходив по таким ссылкам, начинаешь понимать, что С++ изжил себя.

anonymous ()
Ответ на: комментарий от energyclab

Больше не читай эту книгу, там написан полный бред.

mix_mix ★★★★★ ()
Ответ на: комментарий от energyclab

Нет, категорически не пойдёт, автор либо идиот, либо намеренно лжет. Твои две недели размышлений тому следствие. Читай Страуса в оригинале.

mix_mix ★★★★★ ()
Ответ на: комментарий от energyclab

В таких случаях надо обращаться не к книге, а к стандарту и к документации конкретного компилятора. Книга она так, для общего развития.

peregrine ★★★★★ ()
Ответ на: комментарий от energyclab

Мне казалось очевидным что я говорю про версию без nothrow.

slovazap ★★★★★ ()
Последнее исправление: slovazap (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.