Toon posts:

[C++] try...catch (...en finally)*

Pagina: 1
Acties:
  • 186 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Ik heb de tip gekregen om niet met try...except te werken maar met try...catch voor het afvangen van foutmeldingen. Dit heb ik gedaan en nadat ik de help en andere bronnen heb gelezen ben ik tot de volgende code gekomen. Deze code compiled foutloos, maar werkt niet.

C++:
1
2
3
4
5
6
7
8
9
  try
  {
    chdir(dcbDirBrowse->Drive+":\\");
    dlbDirBrowse->Drive = dcbDirBrowse->Drive;
  }
  catch (Exception& e)
  {
    MessageBox(NULL,"Could not access drive.", "Error", MB_ICONEXCLAMATION);
  }


Het is de bedoeling dat wanneer ik in mijn DriveComboBox het a station selecteer en daar geen schijfje in zit een nette melding verschijnt en het programma zich niet ophangt.

Hoe doe ik dit, is er toch iets fout in mijn code?

PS: Ik werk met Borland Builder 4 en heb vernomen dat de help daarvan beknopt is. Dus als iemand wel een fatsoenlijk voorbeeld vindt dan niet gaan lopen klagen dat ik niet goed zoek maar dan staat het gewoon niet in mijn versie.

  • Greyfox
  • Registratie: Januari 2001
  • Laatst online: 30-08 17:13

Greyfox

MSX rulez

Door de code steppen?

MSX 2 rulez more


Verwijderd

Dit gebruik ik (hoewel c++ met dotnet, toch gewoon try-catch:
code:
1
2
3
4
5
6
7
8
9
try
    {
        myConnection->Open();
        myCommand->ExecuteNonQuery();
    }
    catch(SqlException * e)
    {
        Console::Write(e->Message);
    }

Zou het niet zo zijn dat je een andere exception moet gebruiken?

  • D2k
  • Registratie: Januari 2001
  • Laatst online: 31-08 10:19

D2k


idd
leer je code analyseren met de tools die je hebt

Doet iets met Cloud (MS/IBM)


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

het is natuurlijk _wel_ de bedoeling dat een van de 2 statements een exception throw'd als er een error optreedt. Aangezien chdir () een C functie is zal die iig geen exception throwen, en als er al een exception gegooid wordt moet het een Exception of een subclass daarvan zijn (aangezien dat de enige is die je afvangt)

uit de documentatie van chdir ():
Return value
These functions return a value of 0 if successful. A return value of –1 indicates that the specified path could not be found, in which case errno is set to ENOENT.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • [ti]
  • Registratie: Februari 2000
  • Niet online
C++:
1
2
3
4
5
6
7
if (SetCurrentDir(dcbDirBrowse->Drive + ":\\"))
{
  dlbDirBrowse->Drive = dcbDirBrowse->Drive;
  MessageDlg("Dir Changed", mtInformation, TMsgDlgButtons() << mbOK, 0);
}
else
  MessageDlg("Unable to change dir", mtWarning, TMsgDlgButtons() << mbOK, 0);

Verwijderd

Als toch percee wilt throwen/catchen:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
try
{
    if(chdir(dcbDirBrowse->Drive+":\\")) throw "Could not access drive.";
    dlbDirBrowse->Drive = dcbDirBrowse->Drive;
}
catch (const char* msg)
{
    MessageBox(NULL, msg, "Error", MB_ICONEXCLAMATION);
}
catch (...)
{
    MessageBox(NULL, "Something really weird happened, aborting program.", "Fatal Error", B_ICONEXCLAMATION);
    exit(1);
}


offtopic:
PS: dit is niet echt de manier waarop je exceptions maakt, je zou beter een eigen exception class kunnen deriven van de std::exception. Ik post dit om te verduidelijken hoe try/throw/catch werkt.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat ik trouwens wel mis in C++ is finally, maar das misschien een beetje offtopic :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • [ti]
  • Registratie: Februari 2000
  • Niet online
dat heeft c++ builder wel... ( __finally )

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat is geen C++, dat is een extensie van BCB, die MS overigens ook heeft, maar het is gewoon niet portable
Note: Note Structured exception handling works with Win32 for both C and C++ source files. However, it is not specifically designed for C++. You can ensure that your code is more portable by using C++ exception handling. Also, C++ exception handling is more flexible, in that it can handle exceptions of any type. For C++ programs, it is recommended that you use the C++ exception-handling mechanism (try, catch, and throw statements).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

.oisyn schreef op 06 september 2002 @ 14:52:
Wat ik trouwens wel mis in C++ is finally, maar das misschien een beetje offtopic :)
finally is bewust niet opgenomen in C++ omdat je het "opruimwerk" in C++ doet met destructors.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

idd, wat je dus weer dwingt om voor elk loos iets wat opgeruimd moet worden een klasse eromheen te schrijven, wat behoorlijk irritant werkt

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

.oisyn schreef op 06 september 2002 @ 15:13:
idd, wat je dus weer dwingt om voor elk loos iets wat opgeruimd moet worden een klasse eromheen te schrijven, wat behoorlijk irritant werkt
Bekijk het eens andersom :) Wat doe je als een object een exception gooit in een try-block waar ook een "loos iets" opgeruimd moet worden? Op het moment dat je een finally construct toestaat, moet je enorm uitkijken dat het object niet meerdere malen z'n destructor aanroept.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

ik snap niet helemaal wat je bedoeld... kun je een voorbeeld geven?

(ik zie niet in hoe het dubbelop gebeurt: als het object in het try-blok gedefinieerd is dan is ie buiten de scope van het finally-blok, en dus wordt er maar 1 keer de destructor aangeroepen: bij het stack unwinding nadat de exception is gegooid

Is het object buiten het try-blok dedefinieerd dan wordt de destructor uberhaupt niet aangeroepen)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:04
Verwijderd schreef op 06 september 2002 @ 15:08:
[...]

finally is bewust niet opgenomen in C++ omdat je het "opruimwerk" in C++ doet met destructors.


In Delphi heb je wel een finally en je hebt daar ook gewoon destructors.

Ik snap ook niet hoe je 'meerdere keren een destructor zou kunnen aanroepen'. Als je object gedestroyed is door de destructor, kan je het toch geen 2de keer meer gaan destroyen?

https://fgheysels.github.io/


Verwijderd

.oisyn schreef op 06 september 2002 @ 15:24:
(ik zie niet in hoe het dubbelop gebeurt: als het object in het try-blok gedefinieerd is dan is ie buiten de scope van het finally-blok, en dus wordt er maar 1 keer de destructor aangeroepen: bij het stack unwinding nadat de exception is gegooid
Dit is dus niet het geval. Volgens de standaard is een try/catch één statement, met één scope, zie hier.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Ik heb de tip gekregen om niet met try...except te werken maar met try...catch voor het afvangen van foutmeldingen.
?! C++ heeft toch alleen try catch en heeft helemaal geen try except. Ik denk dat jij de Delphi try except hebt gepakt in je C++ code ofzo :)
Dit heb ik gedaan en nadat ik de help en andere bronnen heb gelezen ben ik tot de volgende code gekomen. Deze code compiled foutloos, maar werkt niet.
Wie zegt dat chdir een exceptie gooit?
Met catch (Exception& e) van je alleen de excepties van de klase Exception af.
Met catch (...) van je alle excepties af

We adore chaos because we like to restore order - M.C. Escher


  • johnwoo
  • Registratie: Oktober 1999
  • Laatst online: 21:46

johnwoo

3S-GTE

Verwijderd schreef op 06 september 2002 @ 14:15:
Ik heb de tip gekregen om niet met try...except te werken maar met try...catch voor het afvangen van foutmeldingen. Dit heb ik gedaan en nadat ik de help en andere bronnen heb gelezen ben ik tot de volgende code gekomen. Deze code compiled foutloos, maar werkt niet.

C++:
1
2
3
4
5
6
7
8
9
  try
  {
    chdir(dcbDirBrowse->Drive+":\\");
    dlbDirBrowse->Drive = dcbDirBrowse->Drive;
  }
  catch (Exception& e)
  {
    MessageBox(NULL,"Could not access drive.", "Error", MB_ICONEXCLAMATION);
  }


Het is de bedoeling dat wanneer ik in mijn DriveComboBox het a station selecteer en daar geen schijfje in zit een nette melding verschijnt en het programma zich niet ophangt.

Hoe doe ik dit, is er toch iets fout in mijn code?

PS: Ik werk met Borland Builder 4 en heb vernomen dat de help daarvan beknopt is. Dus als iemand wel een fatsoenlijk voorbeeld vindt dan niet gaan lopen klagen dat ik niet goed zoek maar dan staat het gewoon niet in mijn versie.
Het hangen ligt denk ik aan je incorrecte string concatenatie dcbDirBrowse->Drive+":\\". Ik neem aan dat dcbDirBrowse->Drive een char array is? Op deze manier moet het goed (iig beter ;) ) gaan:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  try
  {
    char buf[256];  // ik geloof dat je hier de MAX_PATH constante
                   // kan gebruiken ipv 256...
    strncpy(buf, dcbDirBrowse->Drive, 256);
    strcat(buf, ":\\");
    chdir(buf);
    dlbDirBrowse->Drive = dcbDirBrowse->Drive; // Over deze assignment
            // ben ik ook niet helemaal zeker; indien het twee char arrays zijn
            // (en geen pointers) dan moet je ook hier een strncpy() gebruiken
  }
  catch (Exception& e)
  {
    MessageBox(NULL,"Could not access drive.", "Error", MB_ICONEXCLAMATION);
  }

4200Wp ZO + 840Wp ZW + 1680Wp NW | 14xIQ7+ + 1xDS3-L | MTVenusE | HWP1


Verwijderd

finally kan wel handig zijn, maar niet voor interne objectcleanups maar voor objectinstances die in de method zelf zijn gecreeerd:

Pseudo:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CMyClass *foo = new CMyClass();

// initialize
try
{
      // do something
      // if all goes well, return
}
catch(...)
{
     // handle exception. 
     // return
}
// als hier een finally toegestaan was, kon je hier voor zowel de 
// geslaagde try als de catch clause foo opruimen:
finally
{
     delete foo;
}

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 06 september 2002 @ 16:00:
[...]

Dit is dus niet het geval. Volgens de standaard is een try/catch één statement, met één scope, zie hier.


het is idd 1 statement, maar niet 1 scope. Kun je het stuk waar staat dat het 1 scope eens copypasten? Want ik zie het niet (Net even getest in MSVC.NET, en daar kan ik in de catch handler ook niet bij de variabelen die gedefinieerd zijn in het bijbehorende try-blok... maar MSVC doet wel vaker rare dingen ;))

de grammatica voor een try-catch blok is
code:
1
2
3
4
5
6
7
8
try-block:
         try compound-statement handler-seq
function-try-block:
         try  ctor-initializeropt function-body handler-seq
handler-seq:
         handler handler-seqopt
handler:
         catch ( exception-declaration ) compound-statement


zoals je ziet staan er verschillende compound-statements in 1 try-catch statement. Als je naar paragraph 6.3 surft dan kun je daar lezen:
A compound statement defines a local scope
Dus helaas, jouw stelling gaat niet op :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 06 september 2002 @ 16:17:
finally kan wel handig zijn, maar niet voor interne objectcleanups maar voor objectinstances die in de method zelf zijn gecreeerd:

Pseudo:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CMyClass *foo = new CMyClass();

// initialize
try
{
      // do something
      // if all goes well, return
}
catch(...)
{
     // handle exception. 
     // return
}
// als hier een finally toegestaan was, kon je hier voor zowel de 
// geslaagde try als de catch clause foo opruimen:
finally
{
     delete foo;
}


idd, maar daar heb je nou net auto_ptr voor :)

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
auto_ptr<CMyClass> foo = new CMyClass();

// initialize
try
{
      // do something
      // if all goes well, return
}
catch(...)
{
     // handle exception. 
     // return
}
// als hier een finally toegestaan was, kon je hier voor zowel de 
// geslaagde try als de catch clause foo opruimen
// maar dat is nu dus niet meer nodig, omdat auto_ptr dat voor je doet


.edit: oeps <CMyClass> werd geparsed als HTML :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

johnwoo schreef op 06 september 2002 @ 16:07:
[...]


Het hangen ligt denk ik aan je incorrecte string concatenatie dcbDirBrowse->Drive+":\\". Ik neem aan dat dcbDirBrowse->Drive een char array is?


aannames zijn fataal, dat het een char * is uit deze context totaal niet op te maken (het kan net zo goed std::string zijn, of Borland's TString (? geen ervaring met BCB) type) :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

.oisyn schreef op 06 september 2002 @ 16:18:
het is idd 1 statement, maar niet 1 scope. Kun je het stuk waar staat dat het 1 scope eens copypasten? Want ik zie het niet (Net even getest in MSVC.NET, en daar kan ik in de catch handler ook niet bij de variabelen die gedefinieerd zijn in het bijbehorende try-blok... maar MSVC doet wel vaker rare dingen ;))
code:
1
2
function-try-block:
         try  ctor-initializeropt function-body handler-seq


Dit is dus een try-clause voor een function/constructor. Om deze te laten werken moeten de parameters van de function/constructor bekend zijn in de catch-blocks:
12The scope and lifetime of the parameters of a function or constructor extend into the handlers of a function-try-block.
Maw. we hebben alletwee half gelijk, en het ligt nogal ingewikkeld :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 06 september 2002 @ 16:36:
[...]


code:
1
2
function-try-block:
         try  ctor-initializeropt function-body handler-seq


Dit is dus een try-clause voor een function/constructor. Om deze te laten werken moeten de parameters van de function/constructor bekend zijn in de catch-blocks:


oh, die productieregel kun je wegdenken omdat hij hier niet van belang is (ik had m zelf even eruit moeten halen :)). Heet gaat tenslotte alleen maar even om die try-catch statement waarvan jij zei dat het 1 scope heeft, en ik dus zeg dat dat niet zo is :)

Dus je krijgt (imho) ook geen problemen met support voor een finally gedeelte, namelijk dat destructoren meerdere keren aangeroepen kunnen worden

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

smart pointers en andere ongein om automatische cleanup te forceren bij het out-of-scope gaan van object refs zijn natuurlijk ook te prefereren. In C# gebruik ik finally eigenlijk alleen voor decidated dispose() calls en het expliciet closen van een database connectie, 2 zaken die puur C# related zijn (de een GC related, de ander aan het feit dat destructors feitelijk niet ondersteunt worden)

Verwijderd

Dan toch maar aantonen wat er fout gaat :)

C++:
1
2
3
4
5
6
7
8
9
try {
    SomeType myObject;  // gooit een exception
}
catch(...) { // <-- Hier gebeurt de evt. stack unwinding en de destructie van myObject.
    std::cout << "Big trouble" << std::endl;
}
finally { // <-- hier zijn alle objects in de try dus iig. al destroyed.
    // Waar is dit dus goed voor, alleen om dingen buiten de try op te ruimen?
}

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

ik geloof niet dat je begrijpt waar finally voor bedoeld is :)

de code in een finally block wordt _altijd_ aangeroepen als de code in het bijbehorende try block is geweest (de enige uitzondering hierop is natuurlijk program termination :)). Dus als er een statement voorbij komt die de control uit een try block verplaatst (return, break, continue of goto) wordt de code in het finally block eerst uitgevoerd

Dat is handig als je een stuk code hebt met veel verschillende control paths (bijvoorbeeld veel geneste if's met return statements), en er moet voordat er daadwerkelijk gereturned wordt eerst nog wat gedaan worden. Je kunt natuurlijk een lokale classe in die functie definieren met een destructor die doet wat jij wilt, maar dan kun je jammer genoeg niet bij de lokale functie variabelen. Ook kun je een variabele bijhouden of er verder gegaan moet worden, maar dat levert imho nogal ranzige code op (je ziet door de if's de code niet meer). Of je kunt voor elke returnstatement je finally code copypasten, maar dat maakt het er niet onderhoudbaarder op. En gebruik van goto is natuurlijk sowieso uit den boze ;)

In die gevallen zijn finally handig. Je stopt je code in een try block, en de opruimcode in de finally, en zodra er vanuit de try gereturned wordt wordt eerst de finally code aangeroepen

aanvulling: ook is het handig bij ingewikkelde program loops waarbij er per increment gewoon veel code uitgevoerd kan worden. Alles in het 3e gedeel van een for lus stoppen is natuurlijk niet echt fijn, en bovendien kun je dan ook niet alles. Een while gebruiken is dan een betere oplossing, maar als je dan een continue doet dan wordt je increment code niet aangeroepen (die staat tenslotte als laatste in de while). Als je dan de code van de lus in een try block gooit, en de increment code in een finally block, dan wordt het dus wel elke keer aangeroepen als je een continue doet :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 06 september 2002 @ 15:08:
finally is bewust niet opgenomen in C++ omdat je het "opruimwerk" in C++ doet met destructors.
Behalve als je integreert met non-C++ elementen zoals de Win32-API waardoor je je zoals oisyn aangeeft scheel staat te encapsuleren.

En de grote vraag als dit de werkelijke reden is: waarom goto wel en finally niet?!? :O

Professionele website nodig?


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 06 september 2002 @ 16:58:
Dan toch maar aantonen wat er fout gaat :)
C++:
1
2
3
4
5
6
7
8
9
try {
    SomeType myObject;  // gooit een exception
}
catch(...) { // <-- Hier gebeurt de evt. stack unwinding en de destructie van myObject.
    std::cout << "Big trouble" << std::endl;
}
finally { // <-- hier zijn alle objects in de try dus iig. al destroyed.
    // Waar is dit dus goed voor, alleen om dingen buiten de try op te ruimen?
}
Maak jij alle objecten van 500+ Kb op de stack aan? Verander die regel eens in:
C++:
1
SomeType* myObject = new myObject;

En nu nog een keertje :)

Nee smart pointers is echt voor gevorderden en mag je bij een taal design dus niet van uit gaan dat het geimplementeerd wordt

Professionele website nodig?


Verwijderd

.oisyn schreef op 06 september 2002 @ 17:09:
ik geloof niet dat je begrijpt waar finally voor bedoeld is :)
Jawel. ik geloof dat je mijn voorbeeld niet begrijpt.
de code in een finally block wordt _altijd_ aangeroepen als de code in het bijbehorende try block is geweest (de enige uitzondering hierop is natuurlijk program termination :)). Dus als er een statement voorbij komt die de control uit een try block verplaatst (return, break, continue of goto) wordt de code in het finally block eerst uitgevoerd
Exact. Het probleem is dat volgens de C++ specs de stack unwound moet zijn (en dus de local objects destroyed) op het moment dat een handler (catch-clause) wordt aangeroepen. Dit houdt dus logischerwijze ook in dat alle locals destroyed moeten zijn voordat de finally-clause bereikt wordt, anders krijgt de finally een andere semantiek wanneer er wel of niet een exception geworpen wordt (en dat is natuurlijk niet werkbaar).

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

ik begrijp je wel, maar jij denkt de hele tijd aan objecten binnen het try-block. Maar denk nou eens aan objecten in de enclosing scope:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
int eenFunctie (HWND hWnd)
{
    try
    {
        // ingewikkelde code die de hWnd gebruikt
        // met allemaal geneste if's en returns
    }
    finally
    {
        SetWindowText (hWnd, "done");
        SetWindowPos (hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    }
}


.edit: topictitel wat bijgeschaafd :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

curry684 schreef op 06 september 2002 @ 17:18:
Maak jij alle objecten van 500+ Kb op de stack aan? Verander die regel eens in:
C++:
1
SomeType* myObject = new myObject;

En nu nog een keertje :)
Als het ff kan gebruik ik geen new en delete, maar laat dat de STL voor me doen. In dit geval zou ik dus een stub-object op de stack plaatsen, en dat stub-object zou via eoa. STL container zijn 500kB op de heap alloceren.
Nee smart pointers is echt voor gevorderden en mag je bij een taal design dus niet van uit gaan dat het geimplementeerd wordt
Ook auto_ptr gebruik ik hoogst zelden, maar het is wel een deel van de specificatie, en dus een deel van de taal.
.oisyn schreef op 06 september 2002 @ 17:30:
ik begrijp je wel, maar jij denkt de hele tijd aan objecten binnen het try-block. Maar denk nou eens aan objecten in de enclosing scope
Dat doe ik, maar jij wilt constant Java-achtige try/catch constructies produceren :)

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int eenFunctie (HWND hWnd)
{
    try
    {
        // critische code, geen if's of returns
    }
    catch(...)
    {
        // foutafhandeling critische code, evt. if's en returns
    }
    SetWindowText (hWnd, "done");
    SetWindowPos (hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    // if's en returns.
}

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

let even op mijn vorige stukje code, daar staat geen catch handler in, en ik ging er dus ook niet vanuit dat er een exception gethrowed ging worden.

Bovendien zijn die 2 functieaanroepen bedoeld als afsluiting, en moeten dus niet voor de if's enzo worden aangeroepen

het equivalent van mijn code zonder finally statement is dan ook zonder try block, alleen dan moet je met goto gaan werken, of extra variabelen bij gaan houden wat het allemaal nogal ingewikkeld kan maken. Feit blijft dat het een handige feature is, en zeker beter dan een goto. En dan kunnen we lang en breed discussieren over hoe het ook kan (zei het met gigantische omweg), maar als dat het argument is dan kunnen een hoop andere features er ook uitgesloopt worden

.edit: had ik al gepost :? Ik had mijn post scherm nog open staan... na ja dan zal ik m wel geedit hebben :D

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 06 september 2002 @ 18:10:
Ook auto_ptr gebruik ik hoogst zelden, maar het is wel een deel van de specificatie, en dus een deel van de taal.
Ik voel hier een oude koe uit de sloot komen.... :D

Toch nog maar een keertje: de standard libs zijn geen onderdeel van de taal C++!!!!!!!!!!!!!!!!!

Ik ben expert in C++, maar ik weet nauwelijks hoe cout werkt (bij wijze van... O-) )... het zijn *geen onlosmakelijke delen*!!! Andersom kan het niet idd.

Professionele website nodig?


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
.oisyn schreef op 06 september 2002 @ 15:13:
idd, wat je dus weer dwingt om voor elk loos iets wat opgeruimd moet worden een klasse eromheen te schrijven, wat behoorlijk irritant werkt
C++ is geen Java of C# hoor. Je gebruikt daarvoor gewoon een template . Bijv. ScopeGuard ( stond in online CUJ artikel van Andrei Alexandrescu )

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

.oisyn schreef op 06 september 2002 @ 18:54:
het equivalent van mijn code zonder finally statement is dan ook zonder try block, alleen dan moet je met goto gaan werken, of extra variabelen bij gaan houden wat het allemaal nogal ingewikkeld kan maken.
Achso! :) Je hebt natuurlijk nog een andere optie, je kunt je methode nog verder structureren tot wat verdere method-calls. Op deze manier gebruik je in mijn optiek een statement oneigenlijk (een try-block om code die niets throwed) en ik zou het dan ook kwalificeren als een hack. :)
curry684 schreef op 07 september 2002 @ 00:41:
Ik voel hier een oude koe uit de sloot komen.... :D

Toch nog maar een keertje: de standard libs zijn geen onderdeel van de taal C++!!!!!!!!!!!!!!!!!
Schrijf jij dan eens een portable Hello World in "pure" C++, dus zonder een lib te gebruiken? De taal C++ is gecastreerd zonder zijn standaard libs, formele definities hier en daar.

Verwijderd

Verwijderd schreef op 06 september 2002 @ 16:58:
Dan toch maar aantonen wat er fout gaat :)
C++:
1
2
3
4
5
6
7
8
9
try {
    SomeType myObject;  // gooit een exception
}
catch(...) { // <-- Hier gebeurt de evt. stack unwinding en de destructie van myObject.
    std::cout << "Big trouble" << std::endl;
}
finally { // <-- hier zijn alle objects in de try dus iig. al destroyed.
    // Waar is dit dus goed voor, alleen om dingen buiten de try op te ruimen?
}
Objects creeeren IN een try-block? try-catch is niet bedoelt als control-flow statement, maar als error-handler. Je punt hierboven is idd dat in het finally block niks meer te doen is, echter objects creeer je normaliter buiten je try block, waarna je IN een try block acties uitvoert die een exception kunnen throwen. In die situaties heb je dus wel degelijk iets aan een finally

Verwijderd

MSalters schreef op 07 september 2002 @ 13:34:
[...]

C++ is geen Java of C# hoor. Je gebruikt daarvoor gewoon een template . Bijv. ScopeGuard ( stond in online CUJ artikel van Andrei Alexandrescu )
Je kunt altijd 3rd party tools gebruiken voor het bouwen van software. Hier gaat het om de taal zelf, of de taal verrijkt zou zijn als finally een deel van de taal zou zijn. Dat C++ geen java of C# is weet iedereen wel, het gaat erom (java heeft vziw ook geen finally) of voordelen gezien in een andere taal, die afgeleid is van C++, in C++ een voordeel zou kunnen zijn.

Dat mensen nu aankomen met "ja maar bij de catch moet de stack unwound zijn" en meer van dat al, dat is voor de developer die in C++ programmeert niet van belang. Wat van belang is, is of er functioneel gezien een zeker gemis is of niet in de taalsyntaxis: zou finally iets toevoegen aan C++, net zoals de in de volgende release van de standaard opgenomen smart pointers een aanvulling van C++ zijn.

Voor centrale clean-up code is finally zeker handig, mede omdat je bij try/catch altijd 2 codepaths hebt waarbij je voor beide toch cleanup code moet uitvoeren. Dat de stack unwound moet zijn is compiler-technisch logisch, maar wellicht moet cleanup code wel iets doen met bv een database connection wat een member is van een object in de class, niet een local-scoped variable.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:04
Verwijderd schreef op 07 september 2002 @ 17:33:
[...]

Objects creeeren IN een try-block? try-catch is niet bedoelt als control-flow statement, maar als error-handler. Je punt hierboven is idd dat in het finally block niks meer te doen is, echter objects creeer je normaliter buiten je try block, waarna je IN een try block acties uitvoert die een exception kunnen throwen. In die situaties heb je dus wel degelijk iets aan een finally


Waarom zou je geen objects binnen het try blok mogen creeëren?
Ik zie eigenlijk ook niet in wat dat met control-flow te maken heeft.. :?

* whoami snapt het laatste al.... ;)

https://fgheysels.github.io/


Verwijderd

Verwijderd schreef op 07 september 2002 @ 17:33:
Objects creeeren IN een try-block? try-catch is niet bedoelt als control-flow statement, maar als error-handler.
Er kan van alles mis gaan tijdens de constructie van een object, en het is dus helemaal niet zo gek dat je tijdens de constructie van een object een exception verwacht...
Je punt hierboven is idd dat in het finally block niks meer te doen is, echter objects creeer je normaliter buiten je try block, waarna je IN een try block acties uitvoert die een exception kunnen throwen. In die situaties heb je dus wel degelijk iets aan een finally
Zie boven. finally als keyword kan zin hebben, maar ik vat nog steeds niet wat het met exception-handling te doen heeft. Alles in een finally block voer je uit onafhankelijk van of er nu een exception gegooid wordt of niet, en is daarom semantisch gezien compleet onafhankelijk van de try en catch clauses. Waarom ze dan syntactisch binden?

Maw: je ziet dat alle pro-finally argumenten uiteindelijk uitdraaien op het propageren van een soort van on-exit handler voor functions, en wat hebben die nu met exception handling te maken?

Verwijderd

Finally als on-exit is uiteraard wel nuttig, wanneer je dmv de catch de functie kunt verlaten en middels een return in de try clause. Door de finally toe te voegen heb je een centrale plek voor het opruimen van handel zonder extra moeite.

Ik ben zelf iemand die lightweight constructors prefereert en niet zware constructors waar van alles fout kan gaan, met alle ellende van dien. Wil je wel zware constructors, dan heb je idd wat aan een try block om je constructorcalls, maar zou dan dit prefereren:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// pseudo
CMyClass *foo;

try
{
        // create object
        foo = new CMyClass();
        // do something

        // done
}
catch(...)
{
        // handle exception
}
finally
{
        delete foo;
}

Verwijderd

Zoals al gezegd los je dit op met auto_ptr:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
try
{
    // create object
    std::auto_ptr<CMyClass> foo(new CMyClass());

    // do something

    // done
}
catch(...)
{
    // handle exception
}


Daarnaast kun je eigen exception classes schrijven die precies de state weerspiegelen waarin het try-block zich bevindt, en dat is natuurlijk de beste oplossing want dan kun je voor elke exception een adequate reactie ondernemen in het betreffende catch-block.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters schreef op 07 september 2002 @ 13:34:
[...]

C++ is geen Java of C# hoor. Je gebruikt daarvoor gewoon een template . Bijv. ScopeGuard ( stond in online CUJ artikel van Andrei Alexandrescu )


Je kunt een template niet een heel blok code meegeven, dus dat is niet echt handig. Dan kun je het stuk code wel in een functie gooien, maar dan kun je weer niet bij de variabelen in de huidige scope. Niet handig dus.

Iedereen denkt hier alleen aan object destruction en dat soort dingen, maar gewoon een lap code als exit handler is ook nuttig (zie mijn voorbeeld van een paar posts terug)

En ook al kun je er omheen coden met (imho) vage constructies, dat neemt nog niet weg dat finally een handige feature van de taal C++ is. (Stel dat je geen references had.. daar is ook makkelijk omheen te coden door pointers te gebruiken, maar is dat gelijk een reden om references niet op te nemen als taal-feature?)
Verwijderd schreef op 07 september 2002 @ 17:44:
(java heeft vziw ook geen finally)
ook java heeft finally :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
curry684 schreef op 07 september 2002 @ 00:41:
[...]

Ik voel hier een oude koe uit de sloot komen.... :D

Toch nog maar een keertje: de standard libs zijn geen onderdeel van de taal C++!!
Tsja, dat mag jij vinden. De ISO C++ commissie denkt daar anders over: die hebben het over de "Core Language" itt non-Core language oftewel Library
Ik ben expert in C++, maar ik weet nauwelijks hoe cout werkt (bij wijze van... O-) )... het zijn *geen onlosmakelijke delen*!!! Andersom kan het niet idd.
Tsja, dat kan je maar beter worden. De consensus binnen ISO is dat de Core Working Group de Library Working Group volgt in ontwikkelingen, dwz dat de LWG bepaalt welke nieuwe features er nodig zijn, en die features die de LWG nodig acht maar zelf niet kan implementeren worden naar de CWG gestuurd.

En wat het andersom betreft, binnen LWG zijn er veel library experts die rustig toegeven dat ze niet weten hoe alle template subtiliteiten werken. Andersom is dat veel minder het geval.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
curry684 schreef op 06 september 2002 @ 17:18:
[...]
Maak jij alle objecten van 500+ Kb op de stack aan? Verander die regel eens in:
C++:
1
SomeType* myObject = new myObject;

En nu nog een keertje :)
Nee smart pointers is echt voor gevorderden en mag je bij een taal design dus niet van uit gaan dat het geimplementeerd wordt
Smart pointers zijn niet voor gevorderden. Dumb pointers, die zijn voor gevorderden.
Sinds Herb Sutter's GotW serie weten we dat raw pointers op de stack niet of nauwelijks excepton-safe te krijgen zijn. Dus dit soort argumenten zijn irrelevant vanuit het standpunt van taal design.
BTW, wanneer heb je objecten met een sizeof > ~1024? Eigenlijk zie ik dat niet meer gebeuren sinds ik de STL gebruik (eigenlijk sinds ik string classes gebruik); de echte data eindigt toch altijd op de heap.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
curry684 schreef op 06 september 2002 @ 17:14:
[...]

Behalve als je integreert met non-C++ elementen zoals de Win32-API waardoor je je zoals oisyn aangeeft scheel staat te encapsuleren.

En de grote vraag als dit de werkelijke reden is: waarom goto wel en finally niet?!? :O
Duh - C compabiliteit, en dat is weer nodig zodat je lex/yacc en verwanten kunt gebruiken. Voor gegenereerde code is goto best handig.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • johnwoo
  • Registratie: Oktober 1999
  • Laatst online: 21:46

johnwoo

3S-GTE

Ik kwam trouwens vandaag een interessant en nogal diepgaand technisch artikel tegen over exception handling in C++. Wellicht al bekend bij sommigen, maar het lijkt me toch wel boeiend genoeg om hier neer te plakken: klik

4200Wp ZO + 840Wp ZW + 1680Wp NW | 14xIQ7+ + 1xDS3-L | MTVenusE | HWP1


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
johnwoo schreef op 12 september 2002 @ 21:26:
Ik kwam trouwens vandaag een interessant en nogal diepgaand technisch artikel tegen over exception handling in C++. Wellicht al bekend bij sommigen, maar het lijkt me toch wel boeiend genoeg om hier neer te plakken: klik
Ouch. Als je al aan het begin leest dat ze een (schaars) x86 register opofferen aan de exception handler - die bijna nooit wordt gebruikt - en iets verder dat ze exception unwinding data op de stack zetten (de EXCEPTION_REGISTRATION structures) met alle daarmee geassocieerde overhead, dan krijg je toch het idee dat MS nog niet zo ver is met exception optimalisatie.

Verder is het artikel fout waar het gaat om het vinden van een catch handler. Er wordt gesuggereerd dat er type_info structuren worden vergeleken. Helaas werkt dit niet, omdat een base-class een andere type-info heeft als z'n derived classes, maar een derived exception class kan wel worden gevangen door een base class catch. (bv catch (std::exception const& e) vangt alle std::length_error's ).

Een derde foutje is minder belangrijk, het artikel gaat er ten onrechte vanuit dat een exception in een dtor tijdens stack unwinding altijd fataal is; dit is niet noodzakelijkerwijs het geval. Een exception binnen een try-catch is niet fataal, ook niet tijdens stack unwinding. Eigenlijk is het pas fataal op het moment dat deze tweede exception samenkomt met de eerste exception, dus dat ze allebei hetzelfde object zouden moeten destructen of dat ze allebei bij dezelfde catch handler komen.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:04
.oisyn schreef op 06 september 2002 @ 17:09:

de code in een finally block wordt _altijd_ aangeroepen als de code in het bijbehorende try block is geweest (de enige uitzondering hierop is natuurlijk program termination :)). Dus als er een statement voorbij komt die de control uit een try block verplaatst (return, break, continue of goto) wordt de code in het finally block eerst uitgevoerd


code in het finally block wordt altijd uitgevoerd, zelfs als er in het try block een statement staat waardoor het programma gestopt wordt.

Illustratie:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Class1
{
   static void Main(string[] args)
   {
            try
            {
                Console.WriteLine ("In het try blok");
                return;
                Console.WriteLine ("na return");
            }
            finally
            {
                Console.WriteLine ("in het finally blok");
            }
   }
}


Heeft als resultaat:
In het try blok
in het finally blok

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

whoami schreef op 13 september 2002 @ 09:47:
[nohtml]
[...]
[/nohtml]

code in het finally block wordt altijd uitgevoerd, zelfs als er in het try block een statement staat waardoor het programma gestopt wordt.


program termination != een return statement

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Class1
{
    static void main (String[] args)
    {
        try
        {
            System.out.println ("In het try blok");
            System.exit (0);
            System.out.println ("na return");
        }
        finally
        {
            System.out.println ("in het finally blok");
        }
    }
}


resultaat:

code:
1
In het try blok


;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

[nohtml]
MSalters schreef op 13 september 2002 @ 09:27:
[...]

Ouch. Als je al aan het begin leest dat ze een (schaars) x86 register opofferen aan de exception handler - die bijna nooit wordt gebruikt
ik vind dit eerlijk gezegd een beetje onzin. fs en gs zijn segment registers die juist vrijwel niet worden gebruikt. En ds, es en ss zijn ook altijd hetzelfde. Want waarvoor zou je in hemelsnaam een ander segment nodig hebben?
- en iets verder dat ze exception unwinding data op de stack zetten (de EXCEPTION_REGISTRATION structures) met alle daarmee geassocieerde overhead, dan krijg je toch het idee dat MS nog niet zo ver is met exception optimalisatie.
ik schrok er ook van toen ik het las, maar aan het begin van het artikel staat ook dat het gebouwd is op MS' __try __except structured exception handling. Ik geloof dat eerlijk gezegd niet zo...

Dat vraagt natuurlijk wel voor een proef op de som :) ben zo terug

.edit: het valt nog best wel mee. Je kunt er natuurlijk niet omheen dat je destructor code voor locale variabelen moet registreren voor objecten met een destructor. Hoe kan de code die de stack unwind anders weten hoe ie de objecten moet opruimen. En zo ontzettend veel overhead is het nou ook weer niet:
code:
1
2
3
4
5
00401403  push        0FFFFFFFFh 
00401405  push        offset $L12665 (454F20h) 
0040140A  mov         eax,dword ptr fs:[00000000h] 
00401410  push        eax  
00401411  mov         dword ptr fs:[0],esp


En dat gebeurt natuurlijk alleen maar als er locale variabelen zijn die opgeruimd moeten worden, anders niet

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1