LINUX.ORG.RU

C++ exception handling


0

0

Каким образом в catch анализируется иерархия классов? С помощью rtti ( dynamic_cast) или как-то еще?


class A
{
  ...
}

class B : A
{
  ...
}

f()
{
    B b;
    throw b;
}

try
{
    f();
}
catch (A& a)
{
   ...
}


Где бы про это почитать? 
    
anonymous

Я имею ввиду, каким образом С++ный runtime догадывается, что B должен ловиться на A?

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

> Я имею ввиду, каким образом С++ный runtime догадывается, что B должен ловиться на A?

когда происходит throw то в этой точке C++ runtime environment имеет две вещи -- статический тип объекта и сам объект.

Если статический тип неполиморфен, то стек раскручивается и ищется дословный catch для этого типа.

Если статический тип полиморфен, то стек раскручивается, а catch ищется тем же образом, как работает dynamic_cast. Любой класс идентифицируется своим vtable -- у C++ runtime environment есть иерархия классов -- для данного статического типа есть фиксированное количество его базовых классов, catch по ним матчится.

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

Спасибо за подробный рассказ. Остается вопрос "где про это почитать".

И еще я не совсем понимаю, занимающийся всеми вышеописанными действиями код живет в libstdc++, в libgcc_c или он генерится компилятором? Речь, естественно, про gcc.

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

Да, по поводу фразы "Любой класс идентифицируется своим vtable". А что такое typeinfo, который генерится для каждого (?) класса, и зачем он нужен? А еще есть typeinfo name ...

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

> Да, по поводу фразы "Любой класс идентифицируется своим vtable".

это относилось к полиморфным классам, у которых есть vtable

> А что такое typeinfo, который генерится для каждого (?) класса, и зачем он нужен?

опять таки -- у объекта есть статический тип. В точке в которой ты берешь typeid -- этот статический тип известен -- поэтому если известно что этот тип неполиморфен, то компилятор просто подставляет объект type_info соответствующий этому статическому типу.

Если же компилятор знает что этот статический тип полиморфен, то он смотрит на реальный vtable объекта и выполняет отображение vtable -> type_info

> А еще есть typeinfo name ...

ну а в объекте класса type_info есть поле name..

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

> и зачем он нужен?

реально он обычно и не нужен -- достаточно вызова виртуальных функций и dynamic_cast

Собственно typeinfo появился в С++ довольно поздно

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

> Если статический тип неполиморфен, то стек раскручивается и ищется 
> дословный catch для этого типа.

Будет выбран первый подходящий catch блок к аргументу которого может 
быть приведен тип кинутого исключения. Полиморфность и RTII тут вообще 
не причем.

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

> Будет выбран первый подходящий catch блок к аргументу которого может быть приведен тип кинутого исключения.

да, точно

> Полиморфность и RTII тут вообще не причем.

при чем -- если тип полиморфен то рассматривается также dynamic_cast

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

> при чем -- если тип полиморфен то рассматривается также dynamic_cast

Как ты себе это представляешь, что значит рассматривается dynamic_cast? 
Читай стандарт, там все написано.

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

>Читай стандарт, там все написано.

О! А можно более конкретную ссылочку?

Я вполне ожидал увидеть rtti, только вот сколько ни копаюсь в исходниках libstdc++, ничего подобного в реальности не наблюдаю.

extern "C" void *
__cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw()
{
  _Unwind_Exception *exceptionObject
    = reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
  __cxa_eh_globals *globals = __cxa_get_globals ();
  __cxa_exception *prev = globals->caughtExceptions;
  __cxa_exception *header = __get_exception_header_from_ue (exceptionObject);
  void* objectp;

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

> О! А можно более конкретную ссылочку?

15.3 Handling an exception [except.handle]

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

> Как ты себе это представляешь, что значит рассматривается dynamic_cast?

точно, не рассматривается.. там только upcast, а не downcast

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

Все это отлично, но я так и не получил (или, что более вероятно, не понял) ответа на свой первый вопрос. Откуда берется знание, что производный класс должен ловиться на catch базового, и где конкретно в gcc-ном runtime (или где-то еще) это знание материализовано?

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

> Откуда берется знание, что производный класс должен ловиться на catch базового,

резюме того что было сказано: половина сказанного мной в начале неверна:) выброшенные исключения матчатся только на основании статического типа.

> и где конкретно в gcc-ном runtime (или где-то еще) это знание материализовано?

видимо в gcc/libstdc++-v3/libsupc++

там есть eh_personality.cc и там ф-ции get_adjusted_ptr и check_exception_spec

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

>выброшенные исключения матчатся только на основании статического типа.

А что, собственно, означает эта фраза? Ведь в mangled name, насколько я понимаю, не содержится никакой информации о наследовании.

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

Место проживания интеллекта я, пожалуй, нашел. Это

bool __vmi_class_type_info:: __do_upcast (const __class_type_info *dst, const void *obj_ptr, __upcast_result &__restrict result) const в файле tinfo.cc

Теперь бы понять что там делается ...

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

> Теперь бы понять что там делается ...

Делаются довольно простые вещи, но для каждого полиморфного класса откуда-то берется индивидуальный __vmi_class_type_info, в котором хранятся указатели на информацию о базовых классах.

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

Главным образом для повышения образовательного уровня.

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