какое исключение ловить?
От: Денис Ильин  
Дата: 13.02.04 14:46
Оценка:
Добрый день. Есть интересный вопросец.

минипрограмка
vector <int> nData;
while(TRUE)
{
  try
  {
    nData.push_back(rand());
  }
  catch(bad_alloc ba) 
  {
    printf("bad alloactor!");
  }
}

что результат её работы в NT-образных платформах одинаковый:
через некоторое время выскакивает мессага "Out of memory"
А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++)
Есть ли какой нибудь иной способ отлавливать невозможность выделить память
(делать это до системы)? (а то следить за свободной памятью геморойно
и неудобно — и вообще не в стиле С++)
Спасибо за ответы.
Исправлено форматирование. Пожалуйста, пользуйтесь тегами [c] ... [/c], [code] ... [/code] и т.п. для выделения фрагментов кода. -- ПК.
Re: какое исключение ловить?
От: jazzer Россия Skype: enerjazzer
Дата: 13.02.04 15:00
Оценка:
Здравствуйте, Денис Ильин, Вы писали:

ДИ>Добрый день. Есть интересный вопросец.


ДИ>минипрограмка


ДИ>vector <int> nData;

ДИ>while(TRUE)
ДИ>{
ДИ> try
ДИ> {
ДИ> nData.push_back(rand());
ДИ> }
ДИ> catch(bad_alloc ba)
ДИ> {
ДИ> printf("bad alloactor!");
ДИ> }
ДИ>}

ДИ>что результат её работы в NT-образных платформах одинаковый:

ДИ>через некоторое время выскакивает мессага "Out of memory"
ДИ>А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++)
ДИ>Есть ли какой нибудь иной способ отлавливать невозможность выделить память
ДИ>(делать это до системы)? (а то следить за свободной памятью геморойно
ДИ>и неудобно — и вообще не в стиле С++)
ДИ>Спасибо за ответы.

дело в том, что винда использует свои собственные не С++ исключение — "структурные исключения", и они не ловятся обычными try/catch

Обычно при сборке проекта можно указать флажок, который приведет к тому, что структурные исключения винды будут транслироваться в С++-исключения, и тогда их можно будет ловить.

Смотри документацию на свой компилятор/линкер.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: какое исключение ловить?
От: 0xFADE США github.com/NotImplemented
Дата: 13.02.04 15:31
Оценка: -1
Здравствуйте, Денис Ильин, Вы писали:

ДИ>Добрый день. Есть интересный вопросец.


ДИ>минипрограмка


ДИ>vector <int> nData;

ДИ>while(TRUE)
ДИ>{
ДИ> try
ДИ> {
ДИ> nData.push_back(rand());
ДИ> }
ДИ> catch(bad_alloc ba)
ДИ> {
ДИ> printf("bad alloactor!");
ДИ> }
ДИ>}

ДИ>что результат её работы в NT-образных платформах одинаковый:

ДИ>через некоторое время выскакивает мессага "Out of memory"
ДИ>Спасибо за ответы.

Боюсь я Вам конкретного ответа не дам, выскажу лишь некоторые соображения.
Соощение появляется из-за того, что система не может осуществить вызов printf()
(Выделить память для размещения параметров в стеке.)

ДИ>А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++)

ДИ>Есть ли какой нибудь иной способ отлавливать невозможность выделить память
ДИ>(делать это до системы)? (а то следить за свободной памятью геморойно
ДИ>и неудобно — и вообще не в стиле С++)

Я долго медитировал над этим абзацем. Можно попросить Вас сформулировать мысль четче?
Отлавливать невозможость выделить память до системы?
Вмешиваться в работу операционной системы в стиле С++?
Насколько я понял Ваши рассуждения, эта проблема надумана, или перед Вами стояла другая задача, которую Вы свели к данной проблеме.
Копайте в сторону kernel API и исходников OS.
Re: какое исключение ловить?
От: Vamp Россия  
Дата: 13.02.04 15:41
Оценка:
1. Исключение надо ловить по ссылке, избегая его создания — вероятно, именно там-то и возникает пресловутая ошибка.
2. Сделать что-то осмысленное в условиях кончившейся памяти вряд ли удасться. Увы.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: какое исключение ловить?
От: maikLa Россия  
Дата: 13.02.04 18:04
Оценка:
Здравствуйте, Vamp, Вы писали:

V>1. Исключение надо ловить по ссылке, избегая его создания — вероятно, именно там-то и возникает пресловутая ошибка.

V>2. Сделать что-то осмысленное в условиях кончившейся памяти вряд ли удасться. Увы.

Все это почти правильно... Только а другом (например list<int>) случае... А в приведеном примере что-то я не совсем понимаю почему из недостатка памяти для большого vectora при realoc-e будет следовать недостаток памяти для чего-либо еще. A bad_alloc нужно ловить действительно по ссылке, стандарт гарантирует достаточное кол-во памяти для одного bad_alloc, а не для его копии...
Re[2]: какое исключение ловить?
От: Денис Ильин  
Дата: 13.02.04 18:12
Оценка:
Флажок при сборке проекта? Что бы такие исключения переводились в отлавливаемые catch-ем?
Мне кажется — это будет дорого стоить, потому что мы таким образом можем испортить в другом
месте, где этого совсем бы не хотелось.
Компилера целых два lcc (наиболее желаемый) и VC 6.
В доке к lcc я ничего путного не нашел. Может = плохо искал?
(за форматирование спасибо)
Re[3]: какое исключение ловить?
От: maikLa Россия  
Дата: 13.02.04 18:20
Оценка:
Здравствуйте, Денис Ильин, Вы писали:

ДИ>Флажок при сборке проекта? Что бы такие исключения переводились в отлавливаемые catch-ем?

ДИ>Мне кажется — это будет дорого стоить, потому что мы таким образом можем испортить в другом
ДИ>месте, где этого совсем бы не хотелось.

Не совсем понятно, что значит испортить? В любом случае exception будет и если ты его раньше не ловил, то и сейчас не поймаешь, если не считать catch(...), но там чаще всего стоит обработчик аля exit...
Re: какое исключение ловить?
От: MaximE Великобритания  
Дата: 13.02.04 18:30
Оценка: 16 (1) +1
Денис Ильин wrote:

> что результат её работы в NT-образных платформах одинаковый:

> через некоторое время выскакивает мессага "Out of memory"
> А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++)
> Есть ли какой нибудь иной способ отлавливать невозможность выделить память
> (делать это до системы)? (а то следить за свободной памятью геморойно
> и неудобно — и вообще не в стиле С++)

Какой компилятор?

В MS студиях new по-умолчанию не бросает std::bad_alloc, а возвращает 0. Чтобы new бросал std::bad_alloc в семерке, если не ошибаюсь, надо включить хедэр <new>. В шестерке нужно установить new_handler.

--
Maxim Egorushkin
MetaCommunications Engineering
http://www.meta-comm.com/engineering/
Posted via RSDN NNTP Server 1.8 beta
Re: какое исключение ловить?
От: Денис Ильин  
Дата: 13.02.04 18:35
Оценка:
так — а вот про ловлю по ссылке я не совсем понял.
(почему нужно ловить по ссылке — я понял, осталось непонятным как написать)

Вот так?
catch(bad_alloc &ba)
{
}


По поводу "напортить" я с вами полностью согласен — это уже из разряда мистики.
Но вопрос остался — про компилеровские настройки.
Я б в МСДН поискал, если б догадался — по каким ключевым словам.
Спасибо. (а у lcc документашка вообще какая то куцая).
Re[2]: какое исключение ловить?
От: maikLa Россия  
Дата: 13.02.04 18:46
Оценка:
Здравствуйте, Денис Ильин, Вы писали:

ДИ>так — а вот про ловлю по ссылке я не совсем понял.

ДИ>(почему нужно ловить по ссылке — я понял, осталось непонятным как написать)

ДИ>Вот так?

ДИ>
ДИ>catch(bad_alloc &ba)
ДИ>{
ДИ>}
ДИ>


Так. Но в приведеном вначале случае можно и так
catch(bad_alloc&)
{
printf(...);
}

поскольку сам экземпляр исключения не используется...

ДИ>Но вопрос остался — про компилеровские настройки.

ДИ>Я б в МСДН поискал, если б догадался — по каким ключевым словам.

Не знаю, я бы сначала new поискал.
Re: какое исключение ловить?
От: Денис Ильин  
Дата: 13.02.04 18:48
Оценка:
у меня new вообще не используется — push_back только. (хотя разве только внутрях push_back-а..)
а push_back всегда возвращает void() (независимо ни от чего).

new_handler — это куды прописать?

По поводу того, что на printf() в стеке места не хватает возражу:

если вместо кучи push_back()-ов сделать один resize() — но большой, то результат будет тот же
хотя на стеке будет памяти — завались.
Re[3]: какое исключение ловить?
От: maikLa Россия  
Дата: 13.02.04 18:51
Оценка:
Упс. Подумал я и вот что мне в голову пришло. В какой момент будет выделена память под экземпляр исключения в следующем случае:
struct Exc { };
try {
    throw Exc();
} catch (Exc e) {
}


Если в момент компиляции, то всё предыдущее сказанное особого смысла не имеет (кроме printf конечно).
Кто знает, подскажите?
Re[4]: какое исключение ловить?
От: Денис Ильин  
Дата: 13.02.04 19:00
Оценка:
ага — пока писал — ответ уже появился.
ну да ладно.
А по поводу надуманности проблемы я не согласен.
Почему? Очень просто.

Работает прога. Долго работает. 20 дней. И в ней куча потоков.
Вдруг один из потоков в силу разных причин не смог выделить push_back-ом память.
И все. Прога слетает. А мне бы хотелось, что б остальные потоки остались работать.
Вот это начальная проблема.
push_back всегда возвращает void. Значит вывод очень простой — нужно ловить исключения.
bad_alloc. Но если в самом простейшем случае исключениt не ловится — то ему грош цена.
Хочу поднять эту цену выше, но вот как — этого я пока не знаю.
Re: какое исключение ловить?
От: What Беларусь  
Дата: 13.02.04 19:05
Оценка:
Здравствуйте, Денис Ильин, Вы писали:

Возможно (я не уверен!!), VC 6 может кидать в таких случаях SEH-исключение.
Тогда, для того, чтобы его можно отлавливать в стиле С++, можно использовать
_set_se_translator.
... << RSDN@Home 1.1.0 stable >>
Re[2]: какое исключение ловить?
От: Денис Ильин  
Дата: 13.02.04 19:08
Оценка:
Окей, я попробую поймать SEH.
Кстати (добавлю) — интересует только линейка NT. Может, это как то упростит дело.
Re[2]: какое исключение ловить?
От: maikLa Россия  
Дата: 13.02.04 19:12
Оценка:
Здравствуйте, Денис Ильин, Вы писали:

ДИ>new_handler — это куды прописать?


Есть такая функция setNewHandler (или что-то около того). Этот самый newHandler — это просто функция, которая вызывается, когда мы не можем выделить память. По-моему по-умолчанию она и генерит bad_alloc. Но чтобы все это заработало точно нужно подключить <new.h>

ДИ>По поводу того, что на printf() в стеке места не хватает возражу:


и действительно, причем здесь стек? имеется ввиду, что если printf требует динаического выделения памяти, то....
Re[3]: какое исключение ловить?
От: _Winnie Россия C++.freerun
Дата: 13.02.04 19:23
Оценка:
Есть геморройный выход — самостоятельно написать свой менедлжер памяти, используя низкоуровневый менеджер памяти, используя VirtalAlloc\VirtalFree и тп.

Поверх него свой new\delete.

Может быть сдезь на rsdn уже есть такой?
Правильно работающая программа — просто частный случай Undefined Behavior
Re[2]: какое исключение ловить?
От: MaximE Великобритания  
Дата: 13.02.04 19:44
Оценка:
Денис Ильин wrote:

> у меня new вообще не используется — push_back только. (хотя разве только внутрях push_back-а..)

> а push_back всегда возвращает void() (независимо ни от чего).
>
> new_handler — это куды прописать?

Ищи в MSDN set_new_handler / _set_new_handler. Вот из своего хэндлера и бросай std::bad_alloc.

--
Maxim Egorushkin
MetaCommunications Engineering
http://www.meta-comm.com/engineering/
Posted via RSDN NNTP Server 1.8 beta
Re: какое исключение ловить?
От: Павел Кузнецов  
Дата: 14.02.04 12:50
Оценка:
Здравствуйте, Денис, Вы писали:

ДИ> что результат её работы в NT-образных платформах одинаковый:

ДИ> через некоторое время выскакивает мессага "Out of memory"

Чуть-чуть модифицировал, чтобы быстрее память съедала:
#include <memory>
#include <vector>
#include <cstdio>

int main()
{
  std::vector<int> nData;
  while(true)
  {
    try
    {
      nData.resize((nData.size() + 1) * 2);
    }
    catch(std::bad_alloc& ba)
    {
      std::printf("bad alloactor!");
      return 1;
    }
  }
}

F:\test\out_of_mem>cl -GX test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

test.cpp
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj

F:\test\out_of_mem>test
bad alloactor!
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: какое исключение ловить?
От: Аноним  
Дата: 15.02.04 12:43
Оценка:
Так у тебя оно вылавливается?
Подробнее пожалуйста — я записываю!
Седьмая студия? Придется её достать. А Винда какая? Тоже интересно.

Я тут поэксперементировал на досуге, и вот что получилось:

Сделал я поиск в MSDN по ключевым словам:
_set_new_handler AND bad_alloc
нашел всего одну тему.
Сделал как там было предложено, а именно:
(решил пока обойтись без STL – для упрощения дела).

int my_new_handler(size_t)
{
  throw bad_alloc();
  return 0;
}

void CNewHandlerDlg::OnButton1() 
{
  _PNH _old_new_handler;
  _old_new_handler = _set_new_handler(my_new_handler);
  

//тут начинается моя самодеятельность//
  int *nX;

  try
  {
    nX = new int[1000000000];
  }
  catch (bad_alloc ba) 
  {
    AfxMessageBox("BAD ALLOC!");
  }

  if(nX)
    delete nX;


    AfxMessageBox("YES!");
  //тут моя самодеятельность заканчивается//


  _set_new_handler(_old_new_handler);
}


Платформа выполнения: WinXP.
В общем: до сообщения “BAD ALLOC” дело не доходит.
Выводимое сообщение = “Out of memory”,

Вся беда в том, что работа будет вестись в сервисе. И ему будет запрещено взаимодействовать с десктопом. А это значит, что это сообщение никто не увидит. А поток будет преостановлен. И единственным способом его завершения станет очень дурацкий метод:TerminateThread. А этого я сильно-сильно не хочу.
В общем – вопрос остается открытым: и ответа я на него пока что не вижу. Можется и вправду 7-ую студию попользовать?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.