Re[8]: Исключения или коды возврата?
От: WPooh США  
Дата: 01.10.02 10:52
Оценка:
Здравствуйте Anatolix, Вы писали:

A>Деструкторы вызываются для локальных переменных. Их настоящий тип

A>известен на момент компиляции и проблем с виртуальностью едесь нет никаких.

A>Если же ты создал объект по new сам его и грохни. Не хочешь возиться с исключениями auto_ptr тебе в помощь.

Ага, это я знаю. Речь совсем не об этом.
Меня интересует не методика написания программ для корректной обработки исключений и освобождения ресурсов, занятых программой, а как компилятор реализует стандарт. Ну, пусть гипотетический компилятор, не в конкретной инкарнации.
Допустим да, есть у нас таблица всех обработчиков исключений, реализованных в программе — сигнатура исключения и список точек входа в соответствующие ловушки.
А вот мне не понятно то, каким образом происходит поиск объектов, сконструированных с момента входа в блок try той ловушки (соответствующей кинутому исключению), которую мы нашли ближайшей для нашего исключения (хотя это тоже нетривиальный момент, без раскрутки стека не обойдется, просто анализ упростится при помощи этой таблицы). Эту вещь я примерно представляю.

Но вот поиск всех сгенеренных объектов между этими двумя точками — тоже собственно, раскрутка стека и анализ кода процедур (ага, вот тут положили на стек пару int-ов и HANDLER — смещаем стек назад. А вот тут у нас заведен класс типа MyClass — нужно позвать деструктор). Деструкторы объектов на стеке компилятор вызывает при нормальном выходе из блока При бросании исключения, видимо, проще тоже позвать их же, но нужно анализировать branch-и разных ветвлений и пр. ерунду. Просто так передать управление на какую-то точку нельзя, нам же просто нужно деструкторы вызвать, а не продолжить работу — после этого блока может идти дальнейшая обработка данных. С другой стороны, код-то уже есть, нужно просто понять где деструкторы заканчиваются и где начинаются деструкторы другого блока, более объемлющего для данной ветки программы.
То ли помещать проверку после каждого окончания блока — а кинули ли исключение? Да — идем на следующий кусок с деструкторами : нет — продолжаем работу.

Например,
long MyMainFunc()
{
  MyClass1 mObj;
  try
  {
    MyClass2 mObj2;
    long lVal = 1;
    char pBuff[1024];
    MyFunc1(1); // can throw exception
  }
  catch(...)
  {
  }
}

long MyFunc1(long param)
{
  MyClass100 mObj100(param);
  if (param>2000)
    return -1;
  if ((param&0x1)==0x1)
  {// pp_1
    MyClass3 mObj3(param);
    long ind=0;
    char pBuff[4];
    if (MyFunc2(param++)==3)// point1
      mObj3.SomeFunc(param);
    else
      mObj3.SomeFunc(param+2);
  } // p_1
  else
  {
    MyClass4 mObj4(param);
    MyFunc2(++param);// point2
    mObj4.OtherFunc(param);
  } //p_2
  MyClass5 mObj5(param);
  mObj5.OtherCoolFunction;
}// p_3

long MyFunc2(long param) throw myException
{
  if (param>1500)
    throw new myException(param);
  param += 5;
  MyFunc1(param);//point3
}// p_4

Я для нагладности привел взаимную рекурсию из двух функций.
В конце концов кинется исключение. То есть, вызовется специальная функция рантайма.
Допустим, есть таблица с указателями на обработчики — там нашли вхождение myException.
В точках point1, point2 и point3 будем находиться во время выхода из функций при раскрутке стека назад.
В точках p_1, p_2, p_3 и p_4 расположен код вызова нужных нам деструкторов. Вот собственно, проблема — то ли раскручивать код назад (допустим, находимся в point1 — назад до точки pp_1 докрутим, а дальше? Анализировать условия ветвления?), то ли прыгать на деструкторы (эти точки p_X еще надо найти).
Видимо, все-таки строится список сконструированных объектов.
Это мое видение, оно может сильно отличаться от истины. Вот я и хотел спросить знатока, как оно внутри устроено. Там же еще наверняка тонкостей выше крыши. Со списками жизнь проще при выкидывании исключения, но есть overhead при нормальной работе.
Это чисто теоретический интерес, не имеющий никакого прикладного значения.

А как работать с файловыми HANDLE, чтобы при генерации исключения файлики закрывались, GDI и прочие ресурсы освобождать — я не это имел в виду. Спасибо, но немножко не оно.

Если запутанно — извините. Можно поконкретнее пообсуждать. Только вот подозреваю, вопрос не будет обсуждаться. Ибо зачем?
Успехов!
К этому моменту у меня внутри 0.5, 0.7, 0.33 (с) НС
Re[9]: Исключения или коды возврата?
От: Anatolix Россия https://www.linkedin.com/in/anatolix/
Дата: 01.10.02 11:26
Оценка: -1
Здравствуйте WPooh, Вы писали:

WP>Если запутанно — извините. Можно поконкретнее пообсуждать. Только вот подозреваю, вопрос не будет обсуждаться. Ибо зачем?


Действительно. если никогда не наблюдал то возьми дизассемблер да посмотри.
Любая проблема дизайна может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев
Re[10]: Исключения или коды возврата?
От: WPooh США  
Дата: 01.10.02 12:55
Оценка:
Здравствуйте Anatolix, Вы писали:

A>Действительно. если никогда не наблюдал то возьми дизассемблер да посмотри.

Спасибо за совет. Посмотрю на досуге.

Ежели появится adb буду рад с ним поболтать.
Кстати, adb, ты не из XDS случаем?
К этому моменту у меня внутри 0.5, 0.7, 0.33 (с) НС
Re[11]: Исключения или коды возврата?
От: Аноним  
Дата: 01.10.02 13:39
Оценка:
Здравствуйте WPooh, Вы писали:

WP>Здравствуйте Anatolix, Вы писали:


A>>Действительно. если никогда не наблюдал то возьми дизассемблер да посмотри.

WP>Спасибо за совет. Посмотрю на досуге.

WP>Ежели появится adb буду рад с ним поболтать.

WP>Кстати, adb, ты не из XDS случаем?

Уже нет -)). Два года назад ушел оттуда.

Собственно я далеко не специалист в этой области. Во-вторых они пишут Java native compiler. А в натуральной Java такой проблемы в принципе нету. Там все объекты создаются в куче и рулятся gc'ом. В XDS компиляторе научились таки в некоторых случаях размешать объекты на стеке, поэтомуй как-то они эту проблему решили. В принципе попробую посмотреть или тупо спросить.

А вообще могу статейку кинуть, которая так и называется "Zero-Overhead Exception Handling Using Metaprogramming", либо в инете её поищи.
Re: Про эффективность.
От: _Winnie Россия C++.freerun
Дата: 11.05.06 14:09
Оценка:
VC71.


конструктор Object при включённых исключениях:

    Object() {}
00401040  push        0FFFFFFFFh 
00401042  push        offset __ehhandler$??0Object@@QAE@XZ (405D59h) 
00401047  mov         eax,dword ptr fs:[00000000h] 
0040104D  push        eax  
0040104E  mov         dword ptr fs:[0],esp 
00401055  push        ecx  
00401056  push        esi  
00401057  mov         esi,ecx 
00401059  mov         dword ptr [esp+4],esi 
0040105D  call        Subobject::Subobject (401000h) 
00401062  lea         ecx,[esi+1] 
00401065  mov         dword ptr [esp+10h],0 
0040106D  call        Subobject::Subobject (401000h) 
00401072  lea         ecx,[esi+2] 
00401075  mov         byte ptr [esp+10h],1 
0040107A  call        Subobject::Subobject (401000h) 
0040107F  lea         ecx,[esi+3] 
00401082  mov         byte ptr [esp+10h],2 
00401087  call        Subobject::Subobject (401000h) 
0040108C  lea         ecx,[esi+4] 
0040108F  mov         byte ptr [esp+10h],3 
00401094  call        Subobject::Subobject (401000h) 
00401099  mov         ecx,dword ptr [esp+8] 
0040109D  mov         eax,esi 
0040109F  pop         esi  
004010A0  mov         dword ptr fs:[0],ecx 
004010A7  add         esp,10h 
004010AA  ret



метод Object2::Init при выключенных исключениях:


    bool Init()
    {
00401020  push        esi  
00401021  push        edi  
00401022  mov         esi,ecx 
        if (!a.Init()) goto error;
00401024  call        Subobject2::Init (401000h) 
00401029  test        al,al 
0040102B  je          error (40105Eh) 
        if (!b.Init()) goto error;
0040102D  lea         edi,[esi+1] 
00401030  mov         ecx,edi 
00401032  call        Subobject2::Init (401000h) 
00401037  test        al,al 
00401039  je          error (40105Eh) 
        if (!c.Init()) goto error;
0040103B  lea         ecx,[esi+2] 
0040103E  call        Subobject2::Init (401000h) 
00401043  test        al,al 
00401045  je          error (40105Eh) 
        if (!b.Init()) goto error;
00401047  mov         ecx,edi 
00401049  call        Subobject2::Init (401000h) 
0040104E  test        al,al 
00401050  je          error (40105Eh) 
          if (!e.Init()) goto error;
00401052  lea         ecx,[esi+4] 
00401055  call        Subobject2::Init (401000h) 
0040105A  test        al,al 
0040105C  jne         error+2Dh (40108Bh) 
error:
        Shutdown();
0040105E  mov         ecx,esi 
00401060  call        Subobject2::Shutdown (401010h) 
00401065  lea         edi,[esi+1] 
00401068  mov         ecx,edi 
0040106A  call        Subobject2::Shutdown (401010h) 
0040106F  lea         ecx,[esi+2] 
00401072  call        Subobject2::Shutdown (401010h) 
00401077  mov         ecx,edi 
00401079  call        Subobject2::Shutdown (401010h) 
0040107E  lea         ecx,[esi+4] 
00401081  call        Subobject2::Shutdown (401010h) 
00401086  pop         edi  
        return false;
00401087  xor         al,al 
00401089  pop         esi  
    }
0040108A  ret              
0040108B  pop         edi  
        return true;
0040108C  mov         al,1 
0040108E  pop         esi  
    }
0040108F  ret


















// test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

int i;



//--------------------------

struct Subobject
{
    __declspec(noinline)Subobject() { if(rand()) throw 0; ++i; }
    __declspec(noinline) ~Subobject() { ++i; }
};

struct Object
{
    Subobject a, b, c, d, e;

    Object() {}
    ~Object() {}
};

void __declspec(noinline) f()
{
    Object a;
}

//--------------------------

struct Subobject2
{
    __declspec(noinline) bool Init() { return rand();  }
    __declspec(noinline) Shutdown() { return rand();  }
};

struct Object2
{
    Subobject2 a, b, c, d, e;

    bool Init()
    {
        if (!a.Init()) goto error;
        if (!b.Init()) goto error;
        if (!c.Init()) goto error;
        if (!b.Init()) goto error;
        if (!e.Init()) goto error;
        return true;
error:
        Shutdown();
        return false;
    }

    void Shutdown() 
    { 
        //объекты Subobject должны быть готовы к Shutdown без инициализации, 
        //что ещё больше усиливает syntax-клаттер и увеличивает asm-код.
        a.Shutdown();
        b.Shutdown(); 
        c.Shutdown();
        b.Shutdown();
        e.Shutdown();
    }
};


bool __declspec(noinline) g()
{
    Object2 b;
    if (b.Init())
        return false;
}


int _tmain(int argc, _TCHAR* argv[])
{    
    f();

    if (!g())
        return 1;
}
Правильно работающая программа — просто частный случай Undefined Behavior
Re[7]: Исключения или коды возврата?
От: Max.Subpixel Россия  
Дата: 12.05.06 12:03
Оценка:
Здравствуйте, WPooh, Вы писали:

WP>Это-твоя машинка. Разработчика. А есть машинки у клиентов. У них может вообще стоять старый пень 100 мегагерцовый с 64 SIMM.

WP>[off]у нас и некоторых разработчиков не уважают — года по три машины не меняют, гады.[/off]

Даже если три года не менять машину — такого старья быть не может...
На такой машине Win 2000 работает очень с трудом....
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best Regards. Max.
Re[8]: Исключения или коды возврата?
От: WPooh США  
Дата: 12.05.06 12:30
Оценка:
Здравствуйте, Max.Subpixel, Вы писали:

MS>Даже если три года не менять машину — такого старья быть не может...

MS>На такой машине Win 2000 работает очень с трудом....
А если посмотреть на год сообщения, то получим 2002-3=1999.
В общем, было такое старье. Trust me.
К этому моменту у меня внутри 0.5, 0.7, 0.33 (с) НС
Re[9]: Исключения или коды возврата?
От: Max.Subpixel Россия  
Дата: 12.05.06 12:37
Оценка:
Здравствуйте, WPooh, Вы писали:

WP>Здравствуйте, Max.Subpixel, Вы писали:


MS>>Даже если три года не менять машину — такого старья быть не может...

MS>>На такой машине Win 2000 работает очень с трудом....
WP>А если посмотреть на год сообщения, то получим 2002-3=1999.
WP>В общем, было такое старье. Trust me.



не заметил

ну правда я помню, что в 99 мы закупали в офис 433 целерон с 14Гб винтами и 17 дюймами мониторов...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best Regards. Max.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.