Страницы

Поиск по вопросам

воскресенье, 31 марта 2019 г.

Возможен ли вызов исключения?

Предположим, где-нибудь, в каком-нибудь месте программы (не в начале), у нас есть следующий код: int a = <некое значение>; Но до этого места, скажем, в нашей программе уже было несколько сот других переменных и программа много раз обращалась к динамической памяти. Возможна ли такая ситуация, что в системе закончится память, и вышеприведенный код приведен к выработке необрабатываемого исключения и аварийному завершению программы? Либо же до этого new[] уже успеет вызвать std::bad_alloc и такая ситуация в принципе невозможна? Другими словами, есть ли гарантия отсутствия исключений в данном случае? Собственно говоря, инструкция int a = some_val просто транслируется в ассемблерную команду наподобии mov eax, ds[index]; т.е. по идее исключение быть и не должно, вопрос только в том, резервируется ли сегмент данных полностью до начала работы программы для всех переменных либо же приобретение ресурсов происходит динамически, в ходе работы программы, как в случае с динамической памятью. Получается, чем больше у нас имен переменных, тем больше индексов в программе, по которым происходит обращение, и тем больше должен быть объем резервируемого сегмента данных. Правда все равно остается вопрос, как запрашивается сегмент данных - либо он представляет некую область в коде программы (секцию данных), либо же размер для сегмента данных и его размер будут получены из системной кучи, при запуске программы.


Ответ

Если я правильно понял вопрос, то есть код: func() { ... int a = 22; ... } В таком случае память для переменной a будет размещаться в стеке и "выделяться" при входе в процедуру func. Я пишу "память выделяется" в кавычках, т.к. при входе в func регистр указателя стека просто будет сдвинут (реально уменьшен) на суммарный объем локальных переменных. Т.о. при обращении к a возможно прерывание по переполнению стека. (Еще вероятнее оно произойдет при вызове первой же функции, если стек в func переполнится). Размер выделяемого сегмента данных под стек (он выделяется при порождении процесса) и возможность управления этим размером зависит от ОС и ее настроек. По умолчанию в Windows это 2MB, в Linux около 10MB. Будет ли средой C++ в таком случае вброшено исключение, откровенно говоря, не знаю. Если интересно, можете поиграться с программкой #include #include #include #include #include
void sigh (int s) { write(1,"catch
",6); exit(1); }
main (int ac, char *av[]) { int sz = av[1]? atoi(av[1]): -1;
while (sz < 1) { printf ("Enter size
"); scanf("%d",&sz); }
struct sigaction sa; memset (&sa,0,sizeof(sa)); sa.sa_handler = sigh; #ifdef ALTST sa.sa_flags = SA_ONSTACK; stack_t ss; ss.ss_sp = malloc(ss.ss_size=1000000); ss.ss_flags = 0; sigaltstack(&ss,NULL); #endif sigaction(SIGSEGV,&sa,NULL);
printf ("Try %d (%x) size
",sz,sz); char a[sz];
a[0] = 'a'; printf ("first
");
a[sz-1] = 'z'; printf ("last
");
exit (0); }
avp@avp-ubu1:~/hashcode$ g++ stacksz.c avp@avp-ubu1:~/hashcode$ ./a.out 10400000 Try 10400000 (9eb100) size first last avp@avp-ubu1:~/hashcode$ ./a.out 10500000 Try 10500000 (a037a0) size Ошибка сегментирования avp@avp-ubu1:~/hashcode$ g++ -DALTST stacksz.c avp@avp-ubu1:~/hashcode$ ./a.out 10500000 Try 10500000 (a037a0) size catch avp@avp-ubu1:~/hashcode$ Идея, надеюсь, понятна. Добавьте ловлю исключений и т.п. крестовые штучки. UPDATE Если кому-то интересно, то можно добавить код struct rlimit lim; int rc = getrlimit(RLIMIT_STACK,&lim); printf ("get = %d stsize: %ld (soft) %ld (hard)
", rc, (long)lim.rlim_cur,(long)lim.rlim_max);
int m = av[2]? atoi(av[2]): 1000000; lim.rlim_cur += m; rc = setrlimit(RLIMIT_STACK,&lim); if (rc < 0) perror("setrlimit"); rc = getrlimit(RLIMIT_STACK,&lim); printf ("get2 = %d stsize: %ld (soft) %ld (hard)
", rc, (long)lim.rlim_cur,(long)lim.rlim_max); и посмотреть, как это работает.

Комментариев нет:

Отправить комментарий