LINUX.ORG.RU

Исключения в С++


0

0

Следующий код

 #include <iostream>

class EXP2 {};

class A
{
        public:
        A() { throw EXP2(); }
};

class B
{
        A a;
        public:
        B();
};

B::B()
try
   : a()
{
}
catch(...)
{
        std::cout << "Exception catch" << std::endl;
}

int main()
{
        B b;
}
 
В FreeBSD приводит к результату,
 $ ./a.out
Exception catch
terminate called after throwing an instance of 'EXP2'
Abort trap: 6 (core dumped) 
Видно что обработчик исключения вызвался, значит по идее исключение перехватывается, и какого хрена стек раскрючивается дальше, что приводит к завершению программы?

Ответ на: комментарий от goose

Если внимательно почиать Страуструпа то «Исключение обработано сразу после входа в его обработчик» и Я исключение EXP2 типа обработал в catch(...) конструктора В. => Должна была только напечататься строчка «Exception catch», какого прога аварийно завершается? Круче если вставить перехватчик в main то исключение там поймается вторично! Фигня откровенная!

mskmsk1985
() автор топика
Ответ на: комментарий от goose

Такаяже мура происходит и при перехвате исключений в дектрукторе:

 A::~A() 
try { 
      throw EXP2(); 
} catch(EXP2 e) { 
      std::cout << "EXP2" << std::endl; 
}
Перехватчик выполняется а исключение проскакивает вверх по стеку. И что? Я типа ни для конструктора ни для деструктора заведомо не могу обрабатывать исключения? Нафига тогда такую семантику (внешний блок try) придумали?

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

У Страуструпа читай пункт 14.4.6.1, там все написана. Это дополнительная возможность, в 99% абсолютно бесполезная. Попробуй найти код реальной программы, где это используется, я ни разу не встречал.

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

try { } catch {} работает всегда одинаково, и в деструкторе тоже
работает необычно только специальная форма для конструктора

не знаю, что у вас там во freebsd за с++..

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

Не для кончтруктора не для деструктора ни в линуксе не в бзде внешний try { } catch {} не работает правильно: он вызывается но исключение проходит вверх по стеку и либо оно будет повторно поймано либо прога рассыпется.

ЗЫ Можещь идти и проверить, а С++ у нас обычный gcc 4.2 , 4.3 , 4.4 результат везде один!

mskmsk1985
() автор топика
Ответ на: комментарий от goose

И че там написана? Я читал, то что она «дополнительная» там НЕ написано, там написано что это позволят ОБРАБОТАТЬ исключения, так че же не обрабатывает?

ЗЫ: давайте не будем про полезная или нет, это уже другой вопрос.

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

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

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

Никогда не говори никогда, особенно если обосновать можешь только посланием читать книги. Они разные бывают и там много разного и интересного пишут.

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

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

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

Про деструкторы все верно, а с конструкторами надо поосторожнее обращаться, но исключения в них - это нормально.

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

Конструктор для класса этого члена вызывается в инициализаторе:

 B::B() 
try 
   : a() 
Классом члена а является А. Конструктор этого класса вызвается в инициализаторе а(), следовательно исключение передается в try блок функции B::B() где оно перехватывается, и ... обработавшись доблестно идет дальше раскручивать стек программы. Это противоречит тому что Страуструп пишет как по английски так и по русски!

Чего хотел сказать-то? что я не так понимаю?

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

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

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

так внешний try и придуман чтобы все исключения в деструкторах и перехватить, а оно не работает. Смысл мне потаенный объясните в перехвате исключения и его безусловной повторной генерации, тем более в деструкторе? Ну мало ли какое я там исключение поймал, вдруг я его могу в деструкторе безболезнено обработать и все за собой нормально очистить! Где логика?

mskmsk1985
() автор топика
Ответ на: комментарий от Booster

Ой не правда. А если так:

class B
{
        A* a;
        public:
        B();
};

B::B()
try
   : a(new A())
{
}
catch(...)
{
        std::cout << "Exception catch" << std::endl;
} 
Может я этот указатель в слечае исключения как-то по другому инициализирую, или что за меня там решили что такого права у меня нет? Если мембер не указатель то Я еще могу согласиться что все Х, но в случае указателя у простите. Про деструктор я уже выше высказался.

ПОЧЕМУ исключение (одно и тоже) перехватывается дважды двумя разными обработчиками когда не повторной явной генерации????

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

У тебя логика с Страуструпом на этот счет расходится. Он считает, что лучше что можно сделать если исключение вылетело из деструктора - это вызвать terminate. Насчет конструкторов, при создании объекта B у тебя произошло исключение, что должно произойти?

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

Если можешь его обработать, не используй список инициализации и ничего дальше не полетит.

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

>Может я этот указатель в слечае исключения как-то по другому инициализирую, или что за меня там решили что такого права у меня нет?
Да, никто не запрещает делать присваивание указателя в теле конструктора.

Про деструктор я уже выше высказался.

Ну мало ли какое я там исключение поймал, вдруг я его могу в деструкторе безболезнено обработать и все за собой нормально очистить! >Где логика?


Вдруг бывает пук. Разрушение объекта это не просто очистка чего-то там, а вызов всех положенных деструкторов, причём правильный вызов.
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.3

Booster ★★
()

ну подумай сам.
запись B b; в main гарантирует тебе что в b будет объект.
B::a гарантирует тебе что в a будет объект.
если конструктор A выбросит исключение - как язык сможет гарантировать что в a - объект? никак. Соответственно и «B b;» тоже самое.

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

>Не для кончтруктора не для деструктора ни в линуксе не в бзде внешний try { } catch {} не работает правильно
прошу прощения, я не понял, что в деструторе тоже разговор о внешнем. все уже сказали, в конструкторе в общем случае по-другому не сделаешь, а в деструкторе по аналогии - если кто-то не смог корректно разрушиться, то и все остальное не может.
а вот например это работает по-другому:

#include <iostream>

int f()
try { throw 1; }
catch (int e) { std::cout << e << "\n"; }

int main() { return f(); }

gavv
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.