|
| C++ exceptions Fra : Stephan Henningsen |
Dato : 01-05-01 20:22 |
|
Hej. Jeg sidder og roder med noget exception-handling, men
det virker ikke efter hensigten. Så prøvede jeg at skrive
et eksempelind fra Deitel-Deitel (2nd ed. s. 683) og det
compiler heller ikke!
Her er koden i en mindre modificeret udgave:
#include <iostream>
#include <stdexcept>
using namespace std;
void function3 () throw ( crap )
{
throw crap("crap in function3()");
}
void function2 () throw ( crap )
{
function3();
}
void function1 () throw ( crap )
{
function2();
}
int main()
{
try {
function1();
}
catch ( crap ex ) {
cerr << "Caught exception: " << ex.what() << "." << endl;
}
return 0;
}
Koden brude kunne compile og ved kørsel smide en exception
'crap' i function3() og til sidst i main() udskrive:
Caught exception: crap in function3().
Jeg kører Debian 2.2 Potato r2.
stephan@levelout $ g++ --version
2.95.2
--
Stephan Henningsen /
/ http://tisprut.dk
| |
Stephan Henningsen (01-05-2001)
| Kommentar Fra : Stephan Henningsen |
Dato : 01-05-01 21:04 |
|
Der mangler jo en exception-klasse! =) Men den var ikke i
det ekspemel i bogen... Smider man den her i toppen, så
virker det. Der er ganske vist en masse grim inline-kode,
men det kan jo bare kyles ud i en anden vil eller hvad man
nu er til...:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class crap {
public:
crap( string str = string("default") ) {
msg.assign(str); }
string what() { return msg; }
private:
string msg;
};
--
Stephan Henningsen /
/ http://tisprut.dk
| |
Stephan Henningsen (01-05-2001)
| Kommentar Fra : Stephan Henningsen |
Dato : 01-05-01 21:11 |
|
Jeg kom til at tænke på noget..
I C returnerer funktioner ofte -1 (i hvert fald i
forbindelse med socket-programmering), hvis der er sket
en fejl et sted under udførslen.
Er exception-handling i C++ en parallel til dette -1-halløj
i C?
--
Stephan Henningsen /
/ http://tisprut.dk
| |
Igor V. Rafienko (02-05-2001)
| Kommentar Fra : Igor V. Rafienko |
Dato : 02-05-01 13:16 |
|
* Stephan Henningsen
> I C returnerer funktioner ofte -1 (i hvert fald i forbindelse med
> socket-programmering), hvis der er sket en fejl et sted under
> udførslen.
I C returnerer funksjoner det som passer. Noen ganger -1 (fx.
socket-funksjoner), andre ganger NULL (malloc), andre ganger et eller
annet positivt tall (printf-familien).
> Er exception-handling i C++ en parallel til dette -1-halløj i C?
Nå vet jeg ikke hva du legger i 'parallell', men exceptions er enda en
mulighet å håndtere feilene på. Noen ganger (som fx. med iostreams)
har programmereren valget mellom å bruke returverdier eller
exceptions.
ivr
--
The only "intuitive" interface is the nipple. After that, it's all learned.
(Bruce Ediger, bediger@teal.csn.org, in comp.os.linux.misc, on X interfaces.)
| |
Stephan Henningsen (02-05-2001)
| Kommentar Fra : Stephan Henningsen |
Dato : 02-05-01 17:32 |
|
On 02 May 2001 14:15:40 +0200, Igor V. Rafienko wrote:
>> Er exception-handling i C++ en parallel til dette -1-halløj i C?
>
>Nå vet jeg ikke hva du legger i 'parallell', men exceptions er enda en
>mulighet å håndtere feilene på. Noen ganger (som fx. med iostreams)
>har programmereren valget mellom å bruke returverdier eller
>exceptions.
Jeps. Men jeg har bare tit haft en funktion til at returnerer
en melding, om operationen gik godt eller om der skete en
fejl. Og "returnere" (manipulere) data via call-by-reference
i parameteroverførslen, fordi return nu blev brugt til det
andet.
Men i går kiggede jeg på noget exception-handling for første
gang i siden jeg blev introduceret til det for meget længe
siden. Og det virker overraskende fornuftigt, må jeg sige!
=) Koden bliver endda tit pænere af det. Og så kan jeg få
mine funktioner til at returnerer det, som det nu var
meningen, de skulle.
Men jeg sidder lidt fast og kunne godt bruge noget hjælp.
Jeg har lavet en exception-klasse som har nogle basale
funktioner. Denne klasse nedarves, der hvor den skal bruges
til andre formål, med den eneste forskel, at constructoren,
skal have en anden default-værdi. Men det virker ikke, som
det skal.
I én klasse, tcpbase, skal exception-klassen tcpbase_err
bruges, og hvis man kalder den uden parametre, siger den
"Fejl i tcpbase", hvis man sprøger den om what() der gik
galt =).
I en anden klasse, tcpclient, skal exception-klassen
tcpclient_err bruges, og pr. default sige "Fejl i
tcpclient". Det er, som jeg ser det, blot et spørgsmål
om at omdefinere constructoren.
Men når jeg smider en exception i tcpclass, siger den "Fejl
i tcpbase."!
Dette er, hvad jeg har nu:
--- fra tcpbase.h ----
class tcpbase_err {
public:
tcpbase_err ( char* m = "error occured in tcpbase" ) {
msg.assign(m);
};
string what() {
return msg;
};
protected:
string msg;
};
--- fra tcpclient.h ---
class tcpclient_err : public tcpbase_err {
public:
tcpclient_err ( char* m = "error occured in tcpclient" ) {
>>>> tcpbase_err::tcpbase_err(m);
}
};
I den mærkerede linie opstår der compiler-fejl:
tcpclient.h: In method `tcpclient_err::tcpclient_err(char * = "error occured in
tcpclient")':
tcpclient.h:47: declaration of `m' shadows a parameter
Men erstatter jeg variablen 'm' med "tjubang!" så skriver
den som sagt "error in tcpbase".
Hvordan får jeg den til at tage imod en parameter og give en
forskellig default besked for hver exception-klasse?
--
Stephan Henningsen /
/ http://tisprut.dk
| |
Igor V. Rafienko (02-05-2001)
| Kommentar Fra : Igor V. Rafienko |
Dato : 02-05-01 16:53 |
|
* Stephan Henningsen
> Jeps. Men jeg har bare tit haft en funktion til at returnerer en
> melding, om operationen gik godt eller om der skete en fejl. Og
> "returnere" (manipulere) data via call-by-reference i
> parameteroverførslen, fordi return nu blev brugt til det andet.
I noen tilfeller gir det mening å returnere et par som forteller om
ting gikk ok og returverdien (for å slippe å finne på magiske
returverdier):
* (setf m (make-hash-table :test #'equal))
Warning: Declaring M special.
#<EQUAL hash table, 0 entries {700A20D}>
* (gethash "flabba" m)
NIL
NIL
* (setf (gethash "flabba" m) 42)
42
* (gethash "flabba" m)
42
T
*
I C++ er det smule gnurete å lage en returverdi som et par (eller,
rettere sagt, det er smule gnurete å bruke det paret), men det er
alltids en mulighet. Det er en grunn til at jeg liker Python:
match, value = fetchValue( structure, key )
if not match:
return
# fi
Som en liten avsporing kan det nevnes at i Python brukes exceptions
når en nøkkel ikke finnes. I C++ finnes også denne muligheten for noen
containers (at() kaster std::out_of_range, iirc).
> Men i går kiggede jeg på noget exception-handling for første gang i
> siden jeg blev introduceret til det for meget længe siden. Og det
> virker overraskende fornuftigt, må jeg sige! =) Koden bliver endda
> tit pænere af det. Og så kan jeg få mine funktioner til at
> returnerer det, som det nu var meningen, de skulle.
Herb Sutter har skrevet en bok under tittelen "Exceptional C++". Boken
inneholder en del kapitler om exceptions i C++. Det er veldig lurt å
lese de kapitlene.
> Men jeg sidder lidt fast og kunne godt bruge noget hjælp. Jeg har
> lavet en exception-klasse som har nogle basale funktioner. Denne
> klasse nedarves, der hvor den skal bruges til andre formål, med den
> eneste forskel, at constructoren, skal have en anden default-værdi.
> Men det virker ikke, som det skal.
Joda, det gjør den. Ikke at jeg liker designet (og ikke at det har så
veldig mye å si), men dog.
> I én klasse, tcpbase, skal exception-klassen tcpbase_err bruges, og
> hvis man kalder den uden parametre, siger den "Fejl i tcpbase", hvis
> man sprøger den om what() der gik galt =). I en anden klasse,
> tcpclient, skal exception-klassen tcpclient_err bruges, og pr.
> default sige "Fejl i tcpclient". Det er, som jeg ser det, blot et
> spørgsmål om at omdefinere constructoren. Men når jeg smider en
> exception i tcpclass, siger den "Fejl i tcpbase."!
[trasker bort på lesesalen og henter EC++ og MEC++]
Det er kanskje ikke så veldig lurt å forandre verdien av default
argumenter i funksjoner som "override"s. Jeg ville ha prøvd en annen
framgangsmåte (dog, for ctors vil det nok være problemfritt).
> --- fra tcpbase.h ----
>
> class tcpbase_err {
> public:
> tcpbase_err ( char* m = "error occured in tcpbase" ) {
> msg.assign(m);
> };
>
> string what() {
> return msg;
> };
>
> protected:
> string msg;
> };
Jeg ville ha arvet fra en passende stdlib klasse, men det er nå så.
Skal denne klassen arves ifra, bør den ha en virtuell dtor.
> --- fra tcpclient.h ---
>
> class tcpclient_err : public tcpbase_err {
> public:
> tcpclient_err ( char* m = "error occured in tcpclient" ) {
> >>>> tcpbase_err::tcpbase_err(m);
> }
> };
Kompileres dette i det hele tatt? IIRC har ikke ctorer et navn og kan
dermed ikke kalles eksplisitt. Det du sikkert mener er:
// forslag 1
tcpclient_err( const char* m = "error occured in tcp client" )
: tcpbase_err( m ) {}
Høres mer fornuftig ut. Du kan lese mer om "initializer lists" i C++
boken din.
Men, som sagt, jeg ville ha prøvd noe sånt:
class Base {
std::string msg;
public:
Base() : msg( "base error" ){}
Base( const char *m ) : msg( m ){}
virtual ~Base(){}
};
class Derived : public Base
{
public:
Derived() : Base( "derived error" ){}
Derived( const char *m ) : Base( m ){}
};
Lager du en Derived uten argumenter, får du 'derived error' i what().
Lager du en Base uten argumenter, får du 'base error' i what().
Noen andre tanker, anyone? Mogens?
> Hvordan får jeg den til at tage imod en parameter og give en
> forskellig default besked for hver exception-klasse?
som i forslag 1. Men jeg ville anbefale å lese EC++, Item 38. Nei, det
er ikke et problem for ctors, men det er noe du bør være klar over.
ivr
--
The only "intuitive" interface is the nipple. After that, it's all learned.
(Bruce Ediger, bediger@teal.csn.org, in comp.os.linux.misc, on X interfaces.)
| |
Mogens Hansen (03-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 03-05-01 16:49 |
|
Hej Stephan,
"Stephan Henningsen" <stephan@levelout.tisprut.dk> wrote in message
news:slrn9f0dka.ba.stephan@levelout.tisprut.dk...
>
>
>
> Men erstatter jeg variablen 'm' med "tjubang!" så skriver
> den som sagt "error in tcpbase".
>
> Hvordan får jeg den til at tage imod en parameter og give en
> forskellig default besked for hver exception-klasse?
>
Hvilken compiler bruger du ?
Det du skrev burde virke.
Det virker på mine compilere (Borland C++Builder V5 på Windows 2000, og gcc
2.96 på Red Hat Linux 7.0).
Men det rummer alligevel et potentielt problem, som muligvis også har noget
at sige i denne sammenhæng.
Når du "catcher by value" i stedet for "by reference" catcher du ikke
nødvendigvis den type der blev smidt - du risikerer at sliced.
Du får lavet en kopi, og exceptions bliver allokeret i noget "magic memory"
som implementationen selv holder styr på, så det er lidt specielt.
I din oprindelige indlæg skrev du
int main()
{
try {
function1();
}
catch ( crap ex ) {
cerr << "Caught exception: " << ex.what() << "." << endl;
}
return 0;
}
hvis du i stedet skriver
int main()
{
try {
function1();
}
catch (const crap& ex ) { // <<<<<<<<<
cerr << "Caught exception: " << ex.what() << "." << endl;
}
return 0;
}
vil jeg tro at det virker.
Venlig hilsen
Mogens Hansen
| |
Stephan Henningsen (07-05-2001)
| Kommentar Fra : Stephan Henningsen |
Dato : 07-05-01 22:40 |
|
On Thu, 3 May 2001 17:49:28 +0200, Mogens Hansen wrote:
>Hej Stephan,
>Hvilken compiler bruger du ?
g++ 2.95.2 under Debian Linux.
>Men det rummer alligevel et potentielt problem, som muligvis også har noget
>at sige i denne sammenhæng.
>Når du "catcher by value" i stedet for "by reference" catcher du ikke
>nødvendigvis den type der blev smidt - du risikerer at sliced.
>Du får lavet en kopi, og exceptions bliver allokeret i noget "magic memory"
>som implementationen selv holder styr på, så det er lidt specielt.
Jeg ved ikke hvad sliced er..
>hvis du i stedet skriver
>
>int main()
>{
>try {
>function1();
>}
>
>catch (const crap& ex ) { // <<<<<<<<<
>cerr << "Caught exception: " << ex.what() << "." << endl;
>}
>
>return 0;
>}
Jeg har prøvet det her:
//
// Exception class for members of class tcpclient.
//
class tcpclient_err {
public:
tcpclient_err ( char* m = "error occured in tcpclient" ) {
msg = m;
};
string what () {
return msg;
};
protected:
string msg;
};
int
main()
{
[...]
try {
client = new tcpclient( host, port );
}
catch ( const tcpclient_err& ex ) {
35: cerr << "Caught exception: " << ex.what() << endl;
delete client;
return TCP_CLIENT_ERR;
}
[...]
}
men det compiler ikke =( :
main.cpp: In function `int main(int, char **)':
main.cpp:35: passing `const tcpclient_err' as `this'
argument of `class string tcpclient_err::what()' discards qualifiers
--
Stephan Henningsen /
/ http://tisprut.dk
| |
Mogens Hansen (08-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 08-05-01 20:52 |
|
Hej Stephan,
"Stephan Henningsen" <stephan@levelout.tisprut.dk> wrote in message
news:slrn9fe5gp.69f.stephan@levelout.tisprut.dk...
> On Thu, 3 May 2001 17:49:28 +0200, Mogens Hansen wrote:
> >Hvilken compiler bruger du ?
>
> g++ 2.95.2 under Debian Linux.
>
>
> >Men det rummer alligevel et potentielt problem, som muligvis også har
noget
> >at sige i denne sammenhæng.
> >Når du "catcher by value" i stedet for "by reference" catcher du ikke
> >nødvendigvis den type der blev smidt - du risikerer at sliced.
> >Du får lavet en kopi, og exceptions bliver allokeret i noget "magic
memory"
> >som implementationen selv holder styr på, så det er lidt specielt.
>
> Jeg ved ikke hvad sliced er..
slice er når man bruger et objekt af en afledt klasse, til at oprette et
objekt af en basis klasse. Herved mister man den ekstra information som det
afledte havde. Det kan f.eks. ske ved overførsel af et objekt by value.
I dit eksempel med exception kunne det være
class base_exception
{
// ...
string msg;
};
class derived_exception : public base_exception
{
// ...
unsigned port_nr;
};
try {
// ...
throw derived_class("unable to open port", port_nr);
}
catch(base_exception x) {
// OOPS - information about "port_nr" lost
// x is _exactly_ of type "base_exception"
}
men hvis man i stedet skriver:
try {
// ...
throw derived_class("unable to open port", port_nr);
}
catch(const base_exception& x) {
// OOPS - information about "port_nr" not lost
// x is of type "base_exception" or derived from "base_exception"
}
>
> >hvis du i stedet skriver
> >
> >int main()
> >{
> >try {
> >function1();
> >}
> >
> >catch (const crap& ex ) { // <<<<<<<<<
> >cerr << "Caught exception: " << ex.what() << "." << endl;
> >}
> >
> >return 0;
> >}
>
>
> Jeg har prøvet det her:
>
>
> //
> // Exception class for members of class tcpclient.
> //
> class tcpclient_err {
> public:
> tcpclient_err ( char* m = "error occured in tcpclient" ) {
> msg = m;
> };
>
> string what () {
> return msg;
> };
>
> protected:
> string msg;
> };
>
>
> int
> main()
> {
> [...]
> try {
> client = new tcpclient( host, port );
> }
>
> catch ( const tcpclient_err& ex ) {
> 35: cerr << "Caught exception: " << ex.what() << endl;
> delete client;
> return TCP_CLIENT_ERR;
> }
> [...]
> }
>
>
> men det compiler ikke =( :
>
> main.cpp: In function `int main(int, char **)':
> main.cpp:35: passing `const tcpclient_err' as `this'
> argument of `class string tcpclient_err::what()' discards qualifiers
>
Umiddelbart vil jeg påstå at der er en fejl i din compiler.
Følgende kode virker med gcc V2.96 på Red Hat Linux 7.0 og med Borland
C++Builder V5.0 og Microsoft Visual C++ V6.0 på Windows 2000 - og jeg mener
at der er i overensstemmelse ANSI C++:
#include <iostream>
#include <string>
#include <cstdlib>
using std::string;
using std::cerr;
class tcpclient_err
{
public:
tcpclient_err(const char* m = "error occured in tcpclient") :
msg(m) {}
const string& what(void) const
{ return msg; }
private:
string msg;
};
int main(void)
{
try {
throw tcpclient_err("not a default error ");
}
catch(const tcpclient_err& x) {
cerr << x.what();
return EXIT_FAILURE;
}
}
Venlig hilsen
Mogens Hansen
| |
Mogens Hansen (03-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 03-05-01 16:50 |
|
Hej Stephan,
"Stephan Henningsen" <stephan@levelout.tisprut.dk> wrote in message
news:slrn9eu61s.1l9.stephan@levelout.tisprut.dk...
>
> Er exception-handling i C++ en parallel til dette -1-halløj
> i C?
Exceptions er en måde at rapportere fejl på i C++, og er således et
alternativ til at returnere fejlkoder.
Fordelene ved exceptions er:
* at man ikke kan undlade at håndtere fejlsituationer
* at fejlhåndteringskoden adskilles tydeligt fra "normal" kode
* fejlhåndteringen blivere nemmere at implementere og teste, fordi det
ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot _at_
der er opstået en fejl.
Ulempen er at det kræver en speciel kodestil. Den er dog velbeskrevet og
simpel. Når man har lært kan det give en væsentligt forbedring af kvaliteten
af den kode man skriver. Der bl.a. anvendelsen af RAII (Resource Aquisistion
Is Initialization).
To væsentlige kilder til beskrivelse af hvordan man programmerer når der kan
smides exception (og det kan der stort set altid når man skriver C++) er:
* "Exceptional C++", Herb Sutter (som Igor Rafienko allerede har nævn)
* "The C++ Programming Language", Bjarne Stroustrup. Kapitlet findes
online på http://www.research.att.com/~bs/3rd_safe0.html
Venlig hilsen
Mogens Hansen
| |
Kent Friis (03-05-2001)
| Kommentar Fra : Kent Friis |
Dato : 03-05-01 18:19 |
|
Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
>Hej Stephan,
>
> * at fejlhåndteringskoden adskilles tydeligt fra "normal" kode
> * fejlhåndteringen blivere nemmere at implementere og teste, fordi det
>ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot _at_
>der er opstået en fejl.
aka. "Generel fejl", som det er kendt fra de fleste windows-programmer.
Mvh
Kent
--
Nu med en e-mail adresse der virker...
| |
Mogens Hansen (03-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 03-05-01 21:12 |
|
Hej Kent,
"Kent Friis" <kfr@fleggaard.dk> wrote in message
news:9cs3tg$q09$1@sunsite.dk...
> Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
> >Hej Stephan,
> >
> > * at fejlhåndteringskoden adskilles tydeligt fra "normal" kode
> > * fejlhåndteringen blivere nemmere at implementere og teste, fordi det
> >ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot
_at_
> >der er opstået en fejl.
>
> aka. "Generel fejl", som det er kendt fra de fleste windows-programmer.
Nej, General Protection Fault kommer fra "undefined behaviour" og har ikke
noget med C++ exceptions at gøre.
C++ exceptions skyldes forudsete fejlsituationer.
"Undefined behaviour" skyldes (formodentlig utilsigtede) programmeringsfejl.
Man kan lave "undefined behaviour" på alle operativsystemer, inkl.
MS-Windows og Linux.
Man kan håndtere General Protection Fault med "Microsoft Structured
Exception Handling".
Jeg mener dog man er bedst tjent med at lade være med at forsøge: man er
kommet i en tilstand som ikke er veldefineret - hvordan kan man fornuftigt
komme ud af det ? Kun ved at bringe sig i en veldefineret tilstand - nemlig
at nedlægge hele programmets state og opbygge den igen.
C++ exceptions har ikke noget med Windows eller CPU exception (traps) at
gøre. C++ exceptions er set fra operativ system og CPU ganske almindelig
eksekvering.
Venlig hilsen
Mogens Hansen
| |
Kent Friis (06-05-2001)
| Kommentar Fra : Kent Friis |
Dato : 06-05-01 20:41 |
|
Den Thu, 3 May 2001 22:11:30 +0200 skrev Mogens Hansen:
>Hej Kent,
>"Kent Friis" <kfr@fleggaard.dk> wrote in message
>news:9cs3tg$q09$1@sunsite.dk...
>> Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
>> >Hej Stephan,
>> >
>> > * at fejlhåndteringskoden adskilles tydeligt fra "normal" kode
>> > * fejlhåndteringen blivere nemmere at implementere og teste, fordi det
>> >ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot
>_at_
>> >der er opstået en fejl.
>>
>> aka. "Generel fejl", som det er kendt fra de fleste windows-programmer.
>
>Nej, General Protection Fault kommer fra "undefined behaviour" og har ikke
>noget med C++ exceptions at gøre.
Det var ikke GPF jeg tænkte på - det er en fejl rapporteret af CPU'en,
om at et program har lavet en seriøs brøler. Den svarer faktisk til
SIGSEGV på mere normale systemer.
Nej, jeg tænkte på alle de andre fejlmeldinger, hvor der bare kommer en
besked om at der er sket en fejl, og så kan man selv begynde at gætte
på om det var et forkert placeret komma, eller nogen der har slettet
en vigtig DLL. En måde at håndtere fejl på, som man meget nem kommer
til at lave med den viden jeg har om exceptions.
try {
do_something();
do_some_more();
even_more();
and_then_some();
}
catch {
msgbox("Generel fejl");
exit(1);
}
(med forbehold for at jeg ikke kender den nøjagtige syntax).
En af grundene til at jeg ikke har lyst til at lære sprog der benytter
exceptions, er at hvis man skal lave en fornuftig fejlhåndtering,
så skal der være en try/catch for hver linie der kan fejle, hvor man
i fx. C kan nøjes med en if()...
Mvh
Kent
--
Nu med en e-mail adresse der virker...
| |
Mogens Hansen (07-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 07-05-01 05:24 |
|
Hej Kent,
"Kent Friis" <kfr@fleggaard.dk> wrote in message
news:9d49bs$p47$1@sunsite.dk...
> Den Thu, 3 May 2001 22:11:30 +0200 skrev Mogens Hansen:
> >Hej Kent,
> >"Kent Friis" <kfr@fleggaard.dk> wrote in message
> >news:9cs3tg$q09$1@sunsite.dk...
> >> Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
> >> >Hej Stephan,
> >> >
> >> > * at fejlhåndteringskoden adskilles tydeligt fra "normal" kode
> >> > * fejlhåndteringen blivere nemmere at implementere og teste, fordi
det
> >> >ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot
> >_at_
> >> >der er opstået en fejl.
> >>
> >> aka. "Generel fejl", som det er kendt fra de fleste windows-programmer.
> >
> >Nej, General Protection Fault kommer fra "undefined behaviour" og har
ikke
> >noget med C++ exceptions at gøre.
>
> Det var ikke GPF jeg tænkte på - det er en fejl rapporteret af CPU'en,
> om at et program har lavet en seriøs brøler. Den svarer faktisk til
> SIGSEGV på mere normale systemer.
Jeg går ud fra at du med "mere normale systemer", mener noget i retningen af
"installeret på flere maskiner" ? :)
>
> Nej, jeg tænkte på alle de andre fejlmeldinger, hvor der bare kommer en
> besked om at der er sket en fejl, og så kan man selv begynde at gætte
> på om det var et forkert placeret komma, eller nogen der har slettet
> en vigtig DLL. En måde at håndtere fejl på, som man meget nem kommer
> til at lave med den viden jeg har om exceptions.
Kan du lige forklare mig, og gruppen hvad det har med C++ exceptions at gøre
at slette et vigtigt DLL eller placeret et komma forkert ?
>
> try {
> do_something();
> do_some_more();
> even_more();
> and_then_some();
> }
> catch {
> msgbox("Generel fejl");
> exit(1);
> }
Sådan noget kode bliver typisk ikke skrevet for at håndtere manglende DLL -
håndteringen ligger i MS-Windows.
>
> (med forbehold for at jeg ikke kender den nøjagtige syntax).
Den ser rimelig nok ud.
>
> En af grundene til at jeg ikke har lyst til at lære sprog der benytter
> exceptions, er at hvis man skal lave en fornuftig fejlhåndtering,
> så skal der være en try/catch for hver linie der kan fejle, hvor man
> i fx. C kan nøjes med en if()...
Det er en almindelig misforståelse - men ikke desto mindre en misforståelse.
Faktisk viser det sig, at man stor set _ikke_ skal skrive try/catch for at
håndtere exceptions rigtigt i C++. Det drejer sig om at tillæge sig en
kodestil, som i det hele taget gør programmerne mere robuste.
Se de referencer til Bjarne Stroustrup og Herb Sutters arbejde, der
tidligere er nævnt i denne tråd.
Husk - der er altid noget at lære hos andre.
For nyligt blev jeg færdig med at læse "The Practice of Programming" af
Brian Kernighan og Rop Pike, som jeg antager kender C _godt_. Det er en
udemærket bog, men en af de ting, som skuffede fælt var netop
fejlhåndteringen som var væsentligt dårligere end hvad man typisk får i C++
med exceptions.
Venlig hilsen
Mogens Hansen
| |
Kent Friis (07-05-2001)
| Kommentar Fra : Kent Friis |
Dato : 07-05-01 16:27 |
|
Den Mon, 7 May 2001 06:24:10 +0200 skrev Mogens Hansen:
>Hej Kent,
>"Kent Friis" <kfr@fleggaard.dk> wrote in message
>news:9d49bs$p47$1@sunsite.dk...
>> Den Thu, 3 May 2001 22:11:30 +0200 skrev Mogens Hansen:
>> >Hej Kent,
>> >"Kent Friis" <kfr@fleggaard.dk> wrote in message
>> >news:9cs3tg$q09$1@sunsite.dk...
>> >> Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
>> >> >Hej Stephan,
>> >> >
>> >> > * at fejlhåndteringskoden adskilles tydeligt fra "normal" kode
>> >> > * fejlhåndteringen blivere nemmere at implementere og teste, fordi
>det
>> >> >ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot
>> >_at_
>> >> >der er opstået en fejl.
>> >>
>> >> aka. "Generel fejl", som det er kendt fra de fleste windows-programmer.
>> >
>> >Nej, General Protection Fault kommer fra "undefined behaviour" og har
>ikke
>> >noget med C++ exceptions at gøre.
>>
>> Det var ikke GPF jeg tænkte på - det er en fejl rapporteret af CPU'en,
>> om at et program har lavet en seriøs brøler. Den svarer faktisk til
>> SIGSEGV på mere normale systemer.
>
>Jeg går ud fra at du med "mere normale systemer", mener noget i retningen af
>"installeret på flere maskiner" ? :)
Nej, jeg mener "der ikke er helt så hjerneskadet".
>> Nej, jeg tænkte på alle de andre fejlmeldinger, hvor der bare kommer en
>> besked om at der er sket en fejl, og så kan man selv begynde at gætte
>> på om det var et forkert placeret komma, eller nogen der har slettet
>> en vigtig DLL. En måde at håndtere fejl på, som man meget nem kommer
>> til at lave med den viden jeg har om exceptions.
>
>Kan du lige forklare mig, og gruppen hvad det har med C++ exceptions at gøre
>at slette et vigtigt DLL eller placeret et komma forkert ?
Det er fejl der skal håndteres - i C ville man teste med if() om hver
ting der kan gå galt, men i exception-baserede sprog ender man ofte
med en stor test omkring en stor klump kode.
>> try {
>> do_something();
>> do_some_more();
>> even_more();
>> and_then_some();
>> }
>> catch {
>> msgbox("Generel fejl");
>> exit(1);
>> }
>
>Sådan noget kode bliver typisk ikke skrevet for at håndtere manglende DLL -
>håndteringen ligger i MS-Windows.
Programmet skal være i stand til at håndtere fejlen, hvis man skal
undgå at det brager ned.
>> (med forbehold for at jeg ikke kender den nøjagtige syntax).
>
>Den ser rimelig nok ud.
>
>> En af grundene til at jeg ikke har lyst til at lære sprog der benytter
>> exceptions, er at hvis man skal lave en fornuftig fejlhåndtering,
>> så skal der være en try/catch for hver linie der kan fejle, hvor man
>> i fx. C kan nøjes med en if()...
>
>Det er en almindelig misforståelse - men ikke desto mindre en misforståelse.
>Faktisk viser det sig, at man stor set _ikke_ skal skrive try/catch for at
>håndtere exceptions rigtigt i C++. Det drejer sig om at tillæge sig en
>kodestil, som i det hele taget gør programmerne mere robuste.
Fejl skal vel håndteres under alle omstændigheder?
>Se de referencer til Bjarne Stroustrup og Herb Sutters arbejde, der
>tidligere er nævnt i denne tråd.
>Husk - der er altid noget at lære hos andre.
Lidt overdrevet at købe en bog om C++, bare for at argumentere for
hvorfor man ikke vil lære det sprog (eller java for den sags skyld).
Mvh
Kent
--
http://www.celebrityshine.com/~kfr - nu med Elgo-billeder
| |
Mogens Hansen (07-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 07-05-01 20:19 |
|
Hej Kent,
det forekommer mig stadig at du blander tingene sammen:
Hvad MS-Windows måtte have af gode og dårlige egenskaber har _ikke_ noget
med C++ exception håndtering at gøre.
Ifølge de tilgængelige kilder som jeg har set er hovedparten af MS-Windows
skrevet i C og ikke i C++.
Hvis du ikke bryder dig om Windows er det jo en ærlig sag.
Der er teoretisk ikke forskel på hvordan og hvilke fejl man kan håndtere med
exceptions i C++ og f.eks. returnering af fejlkoder med tilhørende
if-statements i C.
Det svarer nogenlunde til at der er ikke teoretisk findes nogle programmer,
skrevet i C eller C++ som ikke ville kunne skrives i assembler - hvis man
har tilstrækkeligt meget tid og er tilstrækkeligt omhyggelig.
Der er fejlsituationer som man som applikations udvikler ikke kan teste for,
ligegyldigt hvilket operativsystem man kører under.
Hvis operativsystemet ikke kan tilfredsstile forudsætningerne for at loade
et program, vil/bør operativsystemet give en fejlmelding. Dette sker _inden_
kontrollen bliver overgivet til ens eget program - og dermed inden man før
_chancen_ for at håndtere fejlen.
Prøv f.eks. følgende program:
#include <iostream>
static int large_array[256*1024*1024];
int main(void)
{
std::cout << "Hello big world" << std::endl;
return 0;
}
Hvis operativsystemet ikke kan allokeret den nødvendige mængde hukommelse
for at starte programmet.
Red Hat Linux V7.0 skriver i den situation "Segmentation fault".
MS-Windows 2000 skriver tilsvarende "The system cannot execute the specified
program."
En tilsvarende situation, nemlig operativsystemets manglende evne til at
opfylde et programs krav til at køre, kan man få under MS-Windows med
anvendelsen af DLL'er.
Man kan bruge DLL på 2 måder:
* implicit loaded ved hjælp af import libraries - hvilket klart er mest
normal
* explicit ved kald til systemfunktionen "LoadLibrary"
Hvis et påkrævet DLL ikke findes, og man har baseret sig på implicit
loadning ved hjælp af import libraries, får man _aldrig_ muligheden for at
håndtere fejlen.
"Kent Friis" <kfr@fleggaard.dk> wrote in message
news:9d6erb$hd2$1@sunsite.dk...
> Den Mon, 7 May 2001 06:24:10 +0200 skrev Mogens Hansen:
> >Hej Kent,
> >"Kent Friis" <kfr@fleggaard.dk> wrote in message
> >news:9d49bs$p47$1@sunsite.dk...
> >> Den Thu, 3 May 2001 22:11:30 +0200 skrev Mogens Hansen:
> >> >Hej Kent,
> >> >"Kent Friis" <kfr@fleggaard.dk> wrote in message
> >> >news:9cs3tg$q09$1@sunsite.dk...
> >> >> Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
> >> >> >Hej Stephan,
> >> >> >
> >> >> > * at fejlhåndteringskoden adskilles tydeligt fra "normal" kode
> >> >> > * fejlhåndteringen blivere nemmere at implementere og teste,
fordi
> >det
> >> >> >ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod
blot
> >> >_at_
> >> >> >der er opstået en fejl.
> >> >>
> >> >> aka. "Generel fejl", som det er kendt fra de fleste
windows-programmer.
> >> >
> >> >Nej, General Protection Fault kommer fra "undefined behaviour" og har
> >ikke
> >> >noget med C++ exceptions at gøre.
> >>
> >> Det var ikke GPF jeg tænkte på - det er en fejl rapporteret af CPU'en,
> >> om at et program har lavet en seriøs brøler. Den svarer faktisk til
> >> SIGSEGV på mere normale systemer.
> >
Kan du ikke komme med et helt håndgribeligt og genskabeligt eksempel på
hvordan du får en "Generel Fejl".
Operativ system, version, program etc. ?
Så ved vi hvad du snakker om.
Det som jeg snakker om kan illustreres med følgende eksempel, som er
lige-ud-af-landevejen Standard C++ :
#include <exception>
#include <vector>
#include <iostream>
#include <fstream>
#include <cstdlib>
using std::exception;
using std::vector;
using std::ifstream;
using std::ios_base;
using std::cerr;
int main(void)
{
try {
ifstream is("somefile.txt"); // file might not exist
is.exceptions(ios_base::failbit);
is.exceptions(ios_base::badbit);
vector<char> buffer;
char c;
while(is >> c) {
buffer.push_back(c); // heap allocation might fail
}
return EXIT_SUCCESS;
}
catch(const exception& x) {
cerr << x.what();
return EXIT_FAILURE;
}
}
Her får man en fejlmelding, der afhænger af fejlens type, samtidig med at
alle resourcer _pænt_ frigives til inden programmet afsluttes.
Og ja, hukommelse og file-handles er kun 2 af mange resource typer.
Fejlhåndteringskoden er pænt separeret fra den "normale" kode.
>
> >> Nej, jeg tænkte på alle de andre fejlmeldinger, hvor der bare kommer en
> >> besked om at der er sket en fejl, og så kan man selv begynde at gætte
> >> på om det var et forkert placeret komma, eller nogen der har slettet
> >> en vigtig DLL. En måde at håndtere fejl på, som man meget nem kommer
> >> til at lave med den viden jeg har om exceptions.
> >
> >Kan du lige forklare mig, og gruppen hvad det har med C++ exceptions at
gøre
> >at slette et vigtigt DLL eller placeret et komma forkert ?
>
> Det er fejl der skal håndteres - i C ville man teste med if() om hver
> ting der kan gå galt, men i exception-baserede sprog ender man ofte
> med en stor test omkring en stor klump kode.
>
> >> try {
> >> do_something();
> >> do_some_more();
> >> even_more();
> >> and_then_some();
> >> }
> >> catch {
> >> msgbox("Generel fejl");
> >> exit(1);
> >> }
> >
> >Sådan noget kode bliver typisk ikke skrevet for at håndtere manglende
DLL -
> >håndteringen ligger i MS-Windows.
>
> Programmet skal være i stand til at håndtere fejlen, hvis man skal
> undgå at det brager ned.
Som jeg har gjort rede for ovenfor, kan fejl opstå _inden_ programmet får
overdraget kontrollen, hvorfor det ikke _kan_ håndtere _alle_ fejl.
Operativsystemet _skal_ håndtere nogle af fejlene.
> >
> >> En af grundene til at jeg ikke har lyst til at lære sprog der benytter
> >> exceptions, er at hvis man skal lave en fornuftig fejlhåndtering,
> >> så skal der være en try/catch for hver linie der kan fejle, hvor man
> >> i fx. C kan nøjes med en if()...
> >
> >Det er en almindelig misforståelse - men ikke desto mindre en
misforståelse.
> >Faktisk viser det sig, at man stor set _ikke_ skal skrive try/catch for
at
> >håndtere exceptions rigtigt i C++. Det drejer sig om at tillæge sig en
> >kodestil, som i det hele taget gør programmerne mere robuste.
>
> Fejl skal vel håndteres under alle omstændigheder?
ja, men:
* bliver de altid håndteret ?
* hvad betyder det at "håndtere" ? (fejlmeldinger, resource frigivelse,
korrigerende handlinger etc.)
>
> >Se de referencer til Bjarne Stroustrup og Herb Sutters arbejde, der
> >tidligere er nævnt i denne tråd.
> >Husk - der er altid noget at lære hos andre.
>
> Lidt overdrevet at købe en bog om C++, bare for at argumentere for
> hvorfor man ikke vil lære det sprog (eller java for den sags skyld).
Hvis du kigger tidligere i tråden, vil du se referencen til Bjarne
Stroustrups hjemmeside:
http://www.research.att.com/~bs/3rd_safe0.html
det er praktisk taget gratis - du betaler tiden for download.
Du løber naturligvis en risiko for at lære noget nyt.
Venlig hilsen
Mogens Hansen
| |
Kent Friis (07-05-2001)
| Kommentar Fra : Kent Friis |
Dato : 07-05-01 21:15 |
|
Den Mon, 7 May 2001 21:19:28 +0200 skrev Mogens Hansen:
>Hej Kent,
>
>det forekommer mig stadig at du blander tingene sammen:
>Hvad MS-Windows måtte have af gode og dårlige egenskaber har _ikke_ noget
>med C++ exception håndtering at gøre.
Du misforstår mig. Jeg bruger blot windows som eksempel på hvad en
dårlig vane kan føre til - en dårlig vane, som det er min opfattelse at
man nemt får, hvis man bruger exceptions. En dårlig vane, som giver kode
der minder om flg:
int main() {
try {
initprogram();
mainloop();
cleanup();
}
catch {
error("Generel fejl");
}
}
>Ifølge de tilgængelige kilder som jeg har set er hovedparten af MS-Windows
>skrevet i C og ikke i C++.
Efter størrelsen at dømme, er det skrevet i VB
>Hvis du ikke bryder dig om Windows er det jo en ærlig sag.
Det gør jeg ikke, men det er ikke det der er pointen.
>Der er teoretisk ikke forskel på hvordan og hvilke fejl man kan håndtere med
>exceptions i C++ og f.eks. returnering af fejlkoder med tilhørende
>if-statements i C.
Naturligvis kan man skrive en try/catch blok for hver linie, men koden
vil (IMHO) blive svær at læse. Sværere end de tilsvarende if()'er.
Med if'erne er man derimod nødt til at have en if på hver linie hvor der
skal håndteres en fejl, og derved kommer man nemmere til at tænke over
hvordan fejlen skal håndteres.
>Det svarer nogenlunde til at der er ikke teoretisk findes nogle programmer,
>skrevet i C eller C++ som ikke ville kunne skrives i assembler - hvis man
>har tilstrækkeligt meget tid og er tilstrækkeligt omhyggelig.
Hvis compileren kan...
>Der er fejlsituationer som man som applikations udvikler ikke kan teste for,
>ligegyldigt hvilket operativsystem man kører under.
>Hvis operativsystemet ikke kan tilfredsstile forudsætningerne for at loade
>et program, vil/bør operativsystemet give en fejlmelding. Dette sker _inden_
>kontrollen bliver overgivet til ens eget program - og dermed inden man før
>_chancen_ for at håndtere fejlen.
>Prøv f.eks. følgende program:
>
>#include <iostream>
>
>static int large_array[256*1024*1024];
Dumt med så store globale variable (en lærer ville nok stryge "så
store"). Hvis det var lavet med malloc, var det i det mindste teoretisk
muligt at fange fejlen - og hvis ellers man flytter den ned efter
signal(), så kan SIGSEGV også håndteres.
>int main(void)
>{
> std::cout << "Hello big world" << std::endl;
>
> return 0;
>}
>
>Hvis operativsystemet ikke kan allokeret den nødvendige mængde hukommelse
>for at starte programmet.
>
>Red Hat Linux V7.0 skriver i den situation "Segmentation fault".
En fejlmelding der giver mening (hvis man ved hvad segmentation fault
betyder).
>MS-Windows 2000 skriver tilsvarende "The system cannot execute the specified
>program."
En meget generel fejlmelding.
>En tilsvarende situation, nemlig operativsystemets manglende evne til at
>opfylde et programs krav til at køre, kan man få under MS-Windows med
>anvendelsen af DLL'er.
>Man kan bruge DLL på 2 måder:
> * implicit loaded ved hjælp af import libraries - hvilket klart er mest
>normal
> * explicit ved kald til systemfunktionen "LoadLibrary"
>Hvis et påkrævet DLL ikke findes, og man har baseret sig på implicit
>loadning ved hjælp af import libraries, får man _aldrig_ muligheden for at
>håndtere fejlen.
Det er det samme under *nix, med dlopen() <-> ld.so
>Kan du ikke komme med et helt håndgribeligt og genskabeligt eksempel på
>hvordan du får en "Generel Fejl".
>Operativ system, version, program etc. ?
>Så ved vi hvad du snakker om.
Der er ikke en specifik fejl jeg snakker om. Det er at man (som jeg
ser det) nemt får en dårlig vane.
>Det som jeg snakker om kan illustreres med følgende eksempel, som er
>lige-ud-af-landevejen Standard C++ :
Og dermed halvt-ulæseligt for en C-programmør...
>#include <exception>
>#include <vector>
>#include <iostream>
>#include <fstream>
>#include <cstdlib>
>
>using std::exception;
>using std::vector;
>using std::ifstream;
>using std::ios_base;
>using std::cerr;
>
>int main(void)
>{
> try {
> ifstream is("somefile.txt"); // file might not exist
> is.exceptions(ios_base::failbit);
> is.exceptions(ios_base::badbit);
> vector<char> buffer;
> char c;
> while(is >> c) {
> buffer.push_back(c); // heap allocation might fail
> }
>
> return EXIT_SUCCESS;
> }
> catch(const exception& x) {
> cerr << x.what();
> return EXIT_FAILURE;
> }
>}
>
>Her får man en fejlmelding, der afhænger af fejlens type, samtidig med at
>alle resourcer _pænt_ frigives til inden programmet afsluttes.
>Og ja, hukommelse og file-handles er kun 2 af mange resource typer.
>Fejlhåndteringskoden er pænt separeret fra den "normale" kode.
Som jeg ser det, bliver det ikke frigivet mere pænt end hvis man bare
perror(filename);exit(1);
>Som jeg har gjort rede for ovenfor, kan fejl opstå _inden_ programmet får
>overdraget kontrollen, hvorfor det ikke _kan_ håndtere _alle_ fejl.
>Operativsystemet _skal_ håndtere nogle af fejlene.
Det er ikke dem jeg klager over. OK, eksemplet med DLL'en var nemt at
misforstå.
>> >> En af grundene til at jeg ikke har lyst til at lære sprog der benytter
>> >> exceptions, er at hvis man skal lave en fornuftig fejlhåndtering,
>> >> så skal der være en try/catch for hver linie der kan fejle, hvor man
>> >> i fx. C kan nøjes med en if()...
>> >
>> >Det er en almindelig misforståelse - men ikke desto mindre en
>misforståelse.
>> >Faktisk viser det sig, at man stor set _ikke_ skal skrive try/catch for
>at
>> >håndtere exceptions rigtigt i C++. Det drejer sig om at tillæge sig en
>> >kodestil, som i det hele taget gør programmerne mere robuste.
>>
>> Fejl skal vel håndteres under alle omstændigheder?
>
>ja, men:
> * bliver de altid håndteret ?
Ja, men ikke altid korrekt (En af grundene til at jeg helst
programmerer under *nix).
> * hvad betyder det at "håndtere" ? (fejlmeldinger, resource frigivelse,
>korrigerende handlinger etc.)
Jeg har primært fokus på fejlmeldinger <-> korrigerende handlinger.
Fejlmeldinger kan man altid bruge, men det er ofte mere relevant at
overveje, om programmet selv kan løse problemet - fx. en fil findes
ikke - så skal den måske oprettes. Eller kommaet der er blevet til
et punktum - måske man bare skal spørge brugeren en gang til, i stedet
for at programmet dør med en "generel fejl".
>> >Se de referencer til Bjarne Stroustrup og Herb Sutters arbejde, der
>> >tidligere er nævnt i denne tråd.
>> >Husk - der er altid noget at lære hos andre.
>>
>> Lidt overdrevet at købe en bog om C++, bare for at argumentere for
>> hvorfor man ikke vil lære det sprog (eller java for den sags skyld).
>
>Hvis du kigger tidligere i tråden, vil du se referencen til Bjarne
>Stroustrups hjemmeside:
> http://www.research.att.com/~bs/3rd_safe0.html
>det er praktisk taget gratis - du betaler tiden for download.
>Du løber naturligvis en risiko for at lære noget nyt.
Uden at få løn for det?
Mvh
Kent
--
http://www.celebrityshine.com/~kfr - nu med Elgo-billeder
| |
Mogens Hansen (08-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 08-05-01 08:38 |
|
Hej Kent,
"Kent Friis" <kfr@fleggaard.dk> wrote in message
news:9d6vo0$hgg$1@sunsite.dk...
>
> Du misforstår mig. Jeg bruger blot windows som eksempel på hvad en
Det er ikke bevidst forsøg på at misforstå dig.
Jeg vil blot holde tingene adskilt: C++ exceptions og MS-Windows.
> dårlig vane kan føre til - en dårlig vane, som det er min opfattelse at
> man nemt får, hvis man bruger exceptions. En dårlig vane, som giver kode
> der minder om flg:
>
> int main() {
> try {
> initprogram();
> mainloop();
> cleanup();
> }
> catch {
> error("Generel fejl");
> }
> }
Hvis det er den eneste fejlhåndtering i hele programmet er det ofte
utilstrækkeligt.
Hvis det er til at fange "fejlen som ikke kan ske" er det vel OK ?
>
> >Der er teoretisk ikke forskel på hvordan og hvilke fejl man kan håndtere
med
> >exceptions i C++ og f.eks. returnering af fejlkoder med tilhørende
> >if-statements i C.
>
> Naturligvis kan man skrive en try/catch blok for hver linie, men koden
> vil (IMHO) blive svær at læse. Sværere end de tilsvarende if()'er.
Som jeg sagde tidligere, er det en almindelig fejltagelse, at der skal
skrives try/catch for hver linie - men ikke desto mindre en fejltagelse.
Det modsatte er nærmere tilfældet.
>
> Med if'erne er man derimod nødt til at have en if på hver linie hvor der
> skal håndteres en fejl, og derved kommer man nemmere til at tænke over
> hvordan fejlen skal håndteres.
Prøv at tage et eksempel:
Vi skal lave et program, med en grafisk brugergrænseflade, til at redigere
billeder - måske store billeder.
Der er et menupunkt til at åbne en billed fil, som bliver behandlet i
følgende funktion:
void MyWindow: enImage(void)
{
try {
ImageHandle = ImageLibLoad("large.img"); // allocates multiple
times on heap
ImageLibCompress(ImageHandle); // allocates multiple times on heap
ImageLibZoom(ImageHandle, WindowSize); // allocates multiple times
on heap
}
catch(const bad_alloc&) {
error("Could not load image - not enough memory");
}
catch(...) {
error("Could not load image - unexpected error detected");
}
}
(Jeg har ikke compileret ovenstående, men det er noget i den retning)
Der er ikke behov for at der noget sted i de kaldte biblioteksfunktioner
(som er opfundet til lejligheden) er et eneste check på om allokeringen
fejler (hvis der bruges "operator new"). Det er også uinteressant for
brugeren, hvilken funktion det fejlede i - det er blot vigtigt at det
fejlede og hvorfor.
> >
> >static int large_array[256*1024*1024];
>
> Dumt med så store globale variable (en lærer ville nok stryge "så
> store"). Hvis det var lavet med malloc, var det i det mindste teoretisk
Det var _ikke_ det der var pointen!
Pointen var, at der kan være situationer, hvor operativsystemet ikke kan
opfylde forudsætningen for at starte et program - det være sig for lidt
hukommelse, mangle DLL'er etc.
> >Red Hat Linux V7.0 skriver i den situation "Segmentation fault".
>
> En fejlmelding der giver mening (hvis man ved hvad segmentation fault
> betyder).
>
> >MS-Windows 2000 skriver tilsvarende "The system cannot execute the
specified
> >program."
>
> En meget generel fejlmelding.
Jeg har svært ved at se, at den ene fejlmelding er bedre end den anden.
Ingen giver et hint om hvad problemet er.
Hvis der havde stået noget i retningen af "Not enough available memory to
load program", så havde jeg haft en ide om hvad jeg skulle gøre - lukke
nogle programmer eller købe mere RAM.
>
> >Det som jeg snakker om kan illustreres med følgende eksempel, som er
> >lige-ud-af-landevejen Standard C++ :
>
> Og dermed halvt-ulæseligt for en C-programmør...
Klart - der er naturligvis noget kultur i det.
Jo længere væk man kommer, des sværere bliver det.
Det er formodentligt sværere for en FORTRAN programmør end for en C
programmør.
Tilsvarende er det formodentligt endnu sværere for en narkose sygeplejeske -
sagt med al respekt.
Prøv at se "Learning Standard C++ as a New Language" på
http://www.research.att.com/~bs/new_learning.pdf
> >
> >Her får man en fejlmelding, der afhænger af fejlens type, samtidig med at
> >alle resourcer _pænt_ frigives til inden programmet afsluttes.
> >Og ja, hukommelse og file-handles er kun 2 af mange resource typer.
> >Fejlhåndteringskoden er pænt separeret fra den "normale" kode.
>
> Som jeg ser det, bliver det ikke frigivet mere pænt end hvis man bare
> perror(filename);exit(1);
Jo da - programmet ryder selv op og overlader _ikke_ oprydningen til (mor)
operativsystemet.
Der kan være tale om mange andre typer resourcer, hvor operativsystemet ikke
rydder op:
* Database forbindelser
* Database transaktioner
* Låste mutexer til interprocess kommunikation
etc.
Her er det afgørende for systemets stabilitet, at programmerne gør deres
yderste for at rydde op inden de lukker.
>
> > * hvad betyder det at "håndtere" ? (fejlmeldinger, resource frigivelse,
> >korrigerende handlinger etc.)
>
> Jeg har primært fokus på fejlmeldinger <-> korrigerende handlinger.
> Fejlmeldinger kan man altid bruge, men det er ofte mere relevant at
> overveje, om programmet selv kan løse problemet - fx. en fil findes
> ikke - så skal den måske oprettes. Eller kommaet der er blevet til
Netop, men det kræver at programmet rydder pænt op efter det fejlslagne
forsøg, inden den korrigerende handling påbegyndes.
> >> Lidt overdrevet at købe en bog om C++, bare for at argumentere for
> >> hvorfor man ikke vil lære det sprog (eller java for den sags skyld).
> >
> >Hvis du kigger tidligere i tråden, vil du se referencen til Bjarne
> >Stroustrups hjemmeside:
> > http://www.research.att.com/~bs/3rd_safe0.html
> >det er praktisk taget gratis - du betaler tiden for download.
> >Du løber naturligvis en risiko for at lære noget nyt.
>
> Uden at få løn for det?
Jeg kunne tilbyde at betale dig med glæde - men du vil vel have klingende
mønt
Venlig hilsen
Mogens Hansen
| |
Kent Friis (08-05-2001)
| Kommentar Fra : Kent Friis |
Dato : 08-05-01 18:48 |
|
Den Tue, 8 May 2001 09:38:21 +0200 skrev Mogens Hansen:
>Hej Kent,
>"Kent Friis" <kfr@fleggaard.dk> wrote in message
>news:9d6vo0$hgg$1@sunsite.dk...
>>
>> Du misforstår mig. Jeg bruger blot windows som eksempel på hvad en
>
>Det er ikke bevidst forsøg på at misforstå dig.
>Jeg vil blot holde tingene adskilt: C++ exceptions og MS-Windows.
>
>> dårlig vane kan føre til - en dårlig vane, som det er min opfattelse at
>> man nemt får, hvis man bruger exceptions. En dårlig vane, som giver kode
>> der minder om flg:
>>
>> int main() {
>> try {
>> initprogram();
>> mainloop();
>> cleanup();
>> }
>> catch {
>> error("Generel fejl");
>> }
>> }
>
>Hvis det er den eneste fejlhåndtering i hele programmet er det ofte
>utilstrækkeligt.
Netop. Men det er den type kode man nemt komer til at lave, fordi man
ikke er tvunget til at tænke over det hele tiden. Og jeg synes egentlig
at have set den slags fejl-"håndtering" som hovedargumentet _for_
exceptions. Men måske er det bare mig der læser for meget der er skrevet
af folk der ikke har forstået ideen?
>Hvis det er til at fange "fejlen som ikke kan ske" er det vel OK ?
Så er segmentation fault ca. lige så relevant...
>> >Der er teoretisk ikke forskel på hvordan og hvilke fejl man kan håndtere
>med
>> >exceptions i C++ og f.eks. returnering af fejlkoder med tilhørende
>> >if-statements i C.
>>
>> Naturligvis kan man skrive en try/catch blok for hver linie, men koden
>> vil (IMHO) blive svær at læse. Sværere end de tilsvarende if()'er.
>
>Som jeg sagde tidligere, er det en almindelig fejltagelse, at der skal
>skrives try/catch for hver linie - men ikke desto mindre en fejltagelse.
>Det modsatte er nærmere tilfældet.
Forskellige fejl bør behandles forskelligt - ellers er vi igen ovre
i "Generel fejl".
Derudover er det ofte nødvendigt at problemet er løst, inden man går
videre til næste linie - hvordan vil du gøre det, hvis du kun har en
stor blok - du ved (AFAIK) ikke engang hvilken linie du skulle hoppe
tilbage til, men så er vi måske ovre i noget "resume next" (Yikes)?
>> Med if'erne er man derimod nødt til at have en if på hver linie hvor der
>> skal håndteres en fejl, og derved kommer man nemmere til at tænke over
>> hvordan fejlen skal håndteres.
>
>Prøv at tage et eksempel:
>Vi skal lave et program, med en grafisk brugergrænseflade, til at redigere
>billeder - måske store billeder.
>Der er et menupunkt til at åbne en billed fil, som bliver behandlet i
>følgende funktion:
>
>void MyWindow: enImage(void)
>{
> try {
> ImageHandle = ImageLibLoad("large.img"); // allocates multiple
>times on heap
> ImageLibCompress(ImageHandle); // allocates multiple times on heap
> ImageLibZoom(ImageHandle, WindowSize); // allocates multiple times
>on heap
> }
> catch(const bad_alloc&) {
> error("Could not load image - not enough memory");
> }
> catch(...) {
> error("Could not load image - unexpected error detected");
> }
>}
>
>(Jeg har ikke compileret ovenstående, men det er noget i den retning)
Hvad med noget i retning af:
catch(const file_locked&) {
switch(messagebox("File locked", retry | abort))
case retry:
// resume next ?
case abort:
return
}
}
>Der er ikke behov for at der noget sted i de kaldte biblioteksfunktioner
>(som er opfundet til lejligheden) er et eneste check på om allokeringen
>fejler (hvis der bruges "operator new"). Det er også uinteressant for
>brugeren, hvilken funktion det fejlede i - det er blot vigtigt at det
>fejlede og hvorfor.
>
>> >
>> >static int large_array[256*1024*1024];
>>
>> Dumt med så store globale variable (en lærer ville nok stryge "så
>> store"). Hvis det var lavet med malloc, var det i det mindste teoretisk
>
>Det var _ikke_ det der var pointen!
>Pointen var, at der kan være situationer, hvor operativsystemet ikke kan
>opfylde forudsætningen for at starte et program - det være sig for lidt
>hukommelse, mangle DLL'er etc.
Selvfølgelig, og det kan ikke håndteres fra programmets side, uanset om
man bruger if'er eller exceptions - altså ikke et argument hverken for
eller imod.
>> >Red Hat Linux V7.0 skriver i den situation "Segmentation fault".
>>
>> En fejlmelding der giver mening (hvis man ved hvad segmentation fault
>> betyder).
>>
>> >MS-Windows 2000 skriver tilsvarende "The system cannot execute the
>specified
>> >program."
>>
>> En meget generel fejlmelding.
>
>Jeg har svært ved at se, at den ene fejlmelding er bedre end den anden.
>Ingen giver et hint om hvad problemet er.
>
>Hvis der havde stået noget i retningen af "Not enough available memory to
>load program", så havde jeg haft en ide om hvad jeg skulle gøre - lukke
>nogle programmer eller købe mere RAM.
Segmentation fault referer til hukommelsen på den ene eller den anden
måde, så en blik i manualen burde hjælpe dig _lidt_ på vej.
Der er dog stadig mange muligheder - bug i programmet, defekt ram,
for lidt ram,...
>> >Det som jeg snakker om kan illustreres med følgende eksempel, som er
>> >lige-ud-af-landevejen Standard C++ :
>>
>> Og dermed halvt-ulæseligt for en C-programmør...
>
>Klart - der er naturligvis noget kultur i det.
>Jo længere væk man kommer, des sværere bliver det.
>Det er formodentligt sværere for en FORTRAN programmør end for en C
>programmør.
Sikkert, men nu er jeg heldigvis ikke fortran-programmør
>Tilsvarende er det formodentligt endnu sværere for en narkose sygeplejeske -
>sagt med al respekt.
LOL
>Prøv at se "Learning Standard C++ as a New Language" på
> http://www.research.att.com/~bs/new_learning.pdf
>
>> >
>> >Her får man en fejlmelding, der afhænger af fejlens type, samtidig med at
>> >alle resourcer _pænt_ frigives til inden programmet afsluttes.
>> >Og ja, hukommelse og file-handles er kun 2 af mange resource typer.
>> >Fejlhåndteringskoden er pænt separeret fra den "normale" kode.
>>
>> Som jeg ser det, bliver det ikke frigivet mere pænt end hvis man bare
>> perror(filename);exit(1);
>
>Jo da - programmet ryder selv op og overlader _ikke_ oprydningen til (mor)
>operativsystemet.
I eksemplet var der SVJH kun en fejlmelding, så en evt. oprydning er
overladt til compileren, nøjagtig som ved kald af exit (modsat _exit).
>Der kan være tale om mange andre typer resourcer, hvor operativsystemet ikke
>rydder op:
> * Database forbindelser
> * Database transaktioner
> * Låste mutexer til interprocess kommunikation
>etc.
>Her er det afgørende for systemets stabilitet, at programmerne gør deres
>yderste for at rydde op inden de lukker.
I et objektorienteret sprog vil man nok lade destructoren klare
oprydningen. Den burde compileren sørge for bliver kaldt ved exit(). I
C bør man bruge atexit() til den slags oprydning.
Mvh
Kent
--
http://www.celebrityshine.com/~kfr - nu med Elgo-billeder
| |
Mogens Hansen (08-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 08-05-01 20:48 |
|
"Kent Friis" <kfr@fleggaard.dk> wrote in message
news:9d9bh6$df7$1@sunsite.dk...
> Den Tue, 8 May 2001 09:38:21 +0200 skrev Mogens Hansen:
> >Hej Kent,
> >"Kent Friis" <kfr@fleggaard.dk> wrote in message
> >news:9d6vo0$hgg$1@sunsite.dk...
> >
> >Hvis det er den eneste fejlhåndtering i hele programmet er det ofte
> >utilstrækkeligt.
>
> Netop. Men det er den type kode man nemt komer til at lave, fordi man
> ikke er tvunget til at tænke over det hele tiden. Og jeg synes egentlig
> at have set den slags fejl-"håndtering" som hovedargumentet _for_
> exceptions. Men måske er det bare mig der læser for meget der er skrevet
> af folk der ikke har forstået ideen?
Det håber jeg.
Men et programmeringssprog kan aldrig forhindre at man laver dårlige
programmer.
>
> >Hvis det er til at fange "fejlen som ikke kan ske" er det vel OK ?
>
> Så er segmentation fault ca. lige så relevant...
Ikke forstået.
> >Som jeg sagde tidligere, er det en almindelig fejltagelse, at der skal
> >skrives try/catch for hver linie - men ikke desto mindre en fejltagelse.
> >Det modsatte er nærmere tilfældet.
>
> Forskellige fejl bør behandles forskelligt - ellers er vi igen ovre
> i "Generel fejl".
Det er derfor man kan smide mange _typer_ exceptions, så man kan skelne. Og
man kan selv lave nye typer for at skelne.
F.eks.:
try {
// ...
}
catch(const bad_alloc&) {
// out of memory
}
catch(const DbKeyViolation&) {
}
catch(const NetworkFailure&) {
}
>
> Derudover er det ofte nødvendigt at problemet er løst, inden man går
Netop.
Når der smides en exception, kommer programmet ikke længere i det "normale"
flow.
Programmet forsætter i den først kommende catch på kaldestakken, som kan
behandle exceptions af den pågældende type.
Exceptions kan bruges til at sikrer pre-conditions og invarians.
> videre til næste linie - hvordan vil du gøre det, hvis du kun har en
> stor blok - du ved (AFAIK) ikke engang hvilken linie du skulle hoppe
> tilbage til, men så er vi måske ovre i noget "resume next" (Yikes)?
Der er ikke nogen "resume" mulighed indbygget i exception.
Da exceptions blev designet ind i C++, blev der undersøgt en række virkelige
projekter, hvor man havde prøvet en "resume" strategi, og alle var gået bort
fra det.
Det er beskrevet i bogen "The Design and Evolution of C++", Bjarne
Stroustrup, ISBN 0-201-54330-3, side 390.
>
> Hvad med noget i retning af:
>
> catch(const file_locked&) {
> switch(messagebox("File locked", retry | abort))
> case retry:
> // resume next ?
> case abort:
> return
> }
> }
ja, hvis vi udvider det lidt:
bool try_to_open = true;
while(try_to_open) {
try {
// open file and use it
try_to_open = false; // no exception thrown at this point
}
catch(const file_locked&) {
if(abort == messagebox("File locked", retry | abort)) {
return;
}
// else retry
}
}
> >Det var _ikke_ det der var pointen!
> >Pointen var, at der kan være situationer, hvor operativsystemet ikke kan
> >opfylde forudsætningen for at starte et program - det være sig for lidt
> >hukommelse, mangle DLL'er etc.
>
> Selvfølgelig, og det kan ikke håndteres fra programmets side, uanset om
> man bruger if'er eller exceptions - altså ikke et argument hverken for
> eller imod.
Jeg prøver igen:
Det var et eksempel på en fejlsituation, som et program ikke _kan_ håndtere
fordi det aldrig får chancen. Det andet eksempel var et slettet DLL.
Det var som svar på dit udsagn om at C++ exceptions havde noget at gøre med
hvad du hævde var en hyppigt forekommende "Generel Fejl" under MS-Windows -
f.eks. at nogen har slettet et vigtigt DLL.
C++ exceptions og MS-Windows har, som jeg har sagt flere gange, ikke noget
med hinanden at gøre.
Jeg syntes derfor heller ikke at det var et argument for eller imod
exceptions - så vi er tilsyneladende enige.
> >
> >Jo da - programmet ryder selv op og overlader _ikke_ oprydningen til
(mor)
> >operativsystemet.
>
> I eksemplet var der SVJH kun en fejlmelding, så en evt. oprydning er
> overladt til compileren, nøjagtig som ved kald af exit (modsat _exit).
Nej - oprydningen sker _inden_ fejlmeldingen bliver udskrevet, og har altså
ikke noget med exit at gøre.
Inden en exception bliver catch'et, bliver de objekter som er allokeret på
stakken (automatic allocated) nedlagt.
Det vil sige, at hvis kaldet til "buffer.push_back(c);" kaster en exception
pga. for lidt hukommelse, vil objektet "buffer" først blive nedlagt, hvorved
de resourcer (hukommelse) det er ansvarlig for bliver nedlagt.
Derefter bliver objektet "is" nedlagt hvorved de resourcer (fil-handle og
hukommelse) det er ansvarlig for bliver frigivet.
Først herefter kommer vi til linien, hvor der udskrives en fejlmelding.
Det er grundlaget for et udbredt C++ idiom: "Resource Acquisition Is
Initialization" - RAII.
RAII er en simpel måde at få fejlhåndtering og resource håndtering til at
arbejde godt sammen.
Naturligvis er det C++ compileren der klarer det - automatisk,
velspecificeret og på et fornuftigt tidspunkt.
>
> >Der kan være tale om mange andre typer resourcer, hvor operativsystemet
ikke
> >rydder op:
> > * Database forbindelser
> > * Database transaktioner
> > * Låste mutexer til interprocess kommunikation
> >etc.
> >Her er det afgørende for systemets stabilitet, at programmerne gør deres
> >yderste for at rydde op inden de lukker.
>
> I et objektorienteret sprog vil man nok lade destructoren klare
Jeps - sådan skal det være.
> oprydningen. Den burde compileren sørge for bliver kaldt ved exit(). I
Nej - længe før programmet terminerer.
Nemlig når objektet går ud af scope - for objekter på stakken (automatic
allocated).
Man bør undgå at "hoppe sidelæns" ud af C++ ved hjælp af exit.
Istedet bør man køre "pænt" tilbage på kaldestakken, for derefter at
returnere almindeligt fra main.
> C bør man bruge atexit() til den slags oprydning.
Hvad hvis man ikke vil slutte (f.eks. en 24x7 server) - men prøve at
korrigere fejlsituationen, eller blot afvise at udføre den ønskede handling
?
Kan man fjerne en registrering som man har lavet til atexit ?
Venlig hilsen
Mogens Hansen
| |
Kent Friis (08-05-2001)
| Kommentar Fra : Kent Friis |
Dato : 08-05-01 21:55 |
|
Den Tue, 8 May 2001 21:48:14 +0200 skrev Mogens Hansen:
>"Kent Friis" <kfr@fleggaard.dk> wrote in message
>news:9d9bh6$df7$1@sunsite.dk...
>> Den Tue, 8 May 2001 09:38:21 +0200 skrev Mogens Hansen:
>> >Hej Kent,
>> >"Kent Friis" <kfr@fleggaard.dk> wrote in message
>> >news:9d6vo0$hgg$1@sunsite.dk...
>> >
>> >Hvis det er den eneste fejlhåndtering i hele programmet er det ofte
>> >utilstrækkeligt.
>>
>> Netop. Men det er den type kode man nemt komer til at lave, fordi man
>> ikke er tvunget til at tænke over det hele tiden. Og jeg synes egentlig
>> at have set den slags fejl-"håndtering" som hovedargumentet _for_
>> exceptions. Men måske er det bare mig der læser for meget der er skrevet
>> af folk der ikke har forstået ideen?
>
>Det håber jeg.
>Men et programmeringssprog kan aldrig forhindre at man laver dårlige
>programmer.
>
>>
>> >Hvis det er til at fange "fejlen som ikke kan ske" er det vel OK ?
>>
>> Så er segmentation fault ca. lige så relevant...
>
>Ikke forstået.
Man kan alligevel ikke gøre andet end at konstatere at der er en fejl.
>> >Som jeg sagde tidligere, er det en almindelig fejltagelse, at der skal
>> >skrives try/catch for hver linie - men ikke desto mindre en fejltagelse.
>> >Det modsatte er nærmere tilfældet.
>>
>> Forskellige fejl bør behandles forskelligt - ellers er vi igen ovre
>> i "Generel fejl".
>
>Det er derfor man kan smide mange _typer_ exceptions, så man kan skelne. Og
>man kan selv lave nye typer for at skelne.
>F.eks.:
>
>try {
> // ...
>}
>catch(const bad_alloc&) {
> // out of memory
>}
>catch(const DbKeyViolation&) {
>}
>catch(const NetworkFailure&) {
>}
>
>>
>> Derudover er det ofte nødvendigt at problemet er løst, inden man går
>
>
>Netop.
>Når der smides en exception, kommer programmet ikke længere i det "normale"
>flow.
>Programmet forsætter i den først kommende catch på kaldestakken, som kan
>behandle exceptions af den pågældende type.
>Exceptions kan bruges til at sikrer pre-conditions og invarians.
>
>> videre til næste linie - hvordan vil du gøre det, hvis du kun har en
>> stor blok - du ved (AFAIK) ikke engang hvilken linie du skulle hoppe
>> tilbage til, men så er vi måske ovre i noget "resume next" (Yikes)?
>
>Der er ikke nogen "resume" mulighed indbygget i exception.
>Da exceptions blev designet ind i C++, blev der undersøgt en række virkelige
>projekter, hvor man havde prøvet en "resume" strategi, og alle var gået bort
>fra det.
>Det er beskrevet i bogen "The Design and Evolution of C++", Bjarne
>Stroustrup, ISBN 0-201-54330-3, side 390.
>
>>
>> Hvad med noget i retning af:
>>
>> catch(const file_locked&) {
>> switch(messagebox("File locked", retry | abort))
>> case retry:
>> // resume next ?
>> case abort:
>> return
>> }
>> }
>
>ja, hvis vi udvider det lidt:
>
>bool try_to_open = true;
>while(try_to_open) {
> try {
> // open file and use it
> try_to_open = false; // no exception thrown at this point
> }
> catch(const file_locked&) {
> if(abort == messagebox("File locked", retry | abort)) {
> return;
> }
> // else retry
> }
>}
Så er vi også ovre i at exception-delen fylder mere end kodedelen.
>> >Det var _ikke_ det der var pointen!
>> >Pointen var, at der kan være situationer, hvor operativsystemet ikke kan
>> >opfylde forudsætningen for at starte et program - det være sig for lidt
>> >hukommelse, mangle DLL'er etc.
>>
>> Selvfølgelig, og det kan ikke håndteres fra programmets side, uanset om
>> man bruger if'er eller exceptions - altså ikke et argument hverken for
>> eller imod.
>
>Jeg prøver igen:
>Det var et eksempel på en fejlsituation, som et program ikke _kan_ håndtere
>fordi det aldrig får chancen. Det andet eksempel var et slettet DLL.
>Det var som svar på dit udsagn om at C++ exceptions havde noget at gøre med
>hvad du hævde var en hyppigt forekommende "Generel Fejl" under MS-Windows -
>f.eks. at nogen har slettet et vigtigt DLL.
Jeg tænkte ikke på system-DLL'er, men derimod dem der åbnes med en
funktion svarende til dlopen() - disse kan godt fanges, og afhængig af
hvor vigtige de er, kan fejlen også håndteres uden at programmet behøver
afbrydes.
>C++ exceptions og MS-Windows har, som jeg har sagt flere gange, ikke noget
>med hinanden at gøre.
>Jeg syntes derfor heller ikke at det var et argument for eller imod
>exceptions - så vi er tilsyneladende enige.
>
>> >
>> >Jo da - programmet ryder selv op og overlader _ikke_ oprydningen til
>(mor)
>> >operativsystemet.
>>
>> I eksemplet var der SVJH kun en fejlmelding, så en evt. oprydning er
>> overladt til compileren, nøjagtig som ved kald af exit (modsat _exit).
>
>Nej - oprydningen sker _inden_ fejlmeldingen bliver udskrevet, og har altså
>ikke noget med exit at gøre.
>
>Inden en exception bliver catch'et, bliver de objekter som er allokeret på
>stakken (automatic allocated) nedlagt.
>Det vil sige, at hvis kaldet til "buffer.push_back(c);" kaster en exception
>pga. for lidt hukommelse, vil objektet "buffer" først blive nedlagt, hvorved
>de resourcer (hukommelse) det er ansvarlig for bliver nedlagt.
>Derefter bliver objektet "is" nedlagt hvorved de resourcer (fil-handle og
>hukommelse) det er ansvarlig for bliver frigivet.
>Først herefter kommer vi til linien, hvor der udskrives en fejlmelding.
I ikke-objektorienterede sprog er det kun data der ligger på stakken,
og det vil ikke ændre på fx. forbindelsen til en database. Og uanset
om det er OO eller ej, så vil return eller exit sørge for at
destructoren bliver kaldt, så jeg kan egentlig ikke se det gør den
helt store forskel.
>Det er grundlaget for et udbredt C++ idiom: "Resource Acquisition Is
>Initialization" - RAII.
>RAII er en simpel måde at få fejlhåndtering og resource håndtering til at
>arbejde godt sammen.
>
>Naturligvis er det C++ compileren der klarer det - automatisk,
>velspecificeret og på et fornuftigt tidspunkt.
Det begynder efterhånden at blive lidt for VB-agtigt for min smag.
>> >Der kan være tale om mange andre typer resourcer, hvor operativsystemet
>ikke
>> >rydder op:
>> > * Database forbindelser
>> > * Database transaktioner
>> > * Låste mutexer til interprocess kommunikation
>> >etc.
>> >Her er det afgørende for systemets stabilitet, at programmerne gør deres
>> >yderste for at rydde op inden de lukker.
>>
>> I et objektorienteret sprog vil man nok lade destructoren klare
>
>Jeps - sådan skal det være.
>
>> oprydningen. Den burde compileren sørge for bliver kaldt ved exit(). I
>
>Nej - længe før programmet terminerer.
>Nemlig når objektet går ud af scope - for objekter på stakken (automatic
>allocated).
>Man bør undgå at "hoppe sidelæns" ud af C++ ved hjælp af exit.
>Istedet bør man køre "pænt" tilbage på kaldestakken, for derefter at
>returnere almindeligt fra main.
Det gør da bare C++ endnu mere "underligt"[1].
>> C bør man bruge atexit() til den slags oprydning.
>
>Hvad hvis man ikke vil slutte (f.eks. en 24x7 server) - men prøve at
>korrigere fejlsituationen, eller blot afvise at udføre den ønskede handling
>?
Så har man nok slet ikke lyst til at miste fx. sin databaseforbindelse.
>Kan man fjerne en registrering som man har lavet til atexit ?
Det ser ikke ud til det.
Mvh
Kent
[1] Jeg var lige ved at skrive "tåbeligt"...
--
http://www.celebrityshine.com/~kfr/ - nu med Elgo-billeder
| |
Mogens Hansen (09-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 09-05-01 14:21 |
|
"Kent Friis" <kfr@fleggaard.dk> wrote in message
news:9d9mef$jgl$1@sunsite.dk...
>
> Så er vi også ovre i at exception-delen fylder mere end kodedelen.
Måske - måske ikke.
Det er ikke ualmindeligt at fejlhåndtering fylder en væsentlig del af et
stabilt program.
Er der noget forkert i det ?
>
> I ikke-objektorienterede sprog er det kun data der ligger på stakken,
> og det vil ikke ændre på fx. forbindelsen til en database. Og uanset
> om det er OO eller ej, så vil return eller exit sørge for at
> destructoren bliver kaldt, så jeg kan egentlig ikke se det gør den
> helt store forskel.
Det er ikke rigtigt for C++ (og heller ikke for Java og C# - for der er ikke
nogen
destructor).
Ved exit bliver destructorer til alle _globale_ objekter (static allocated)
kaldt, men destructoren bliver ikke kaldt for objekter på stakken (automatic
allocated).
Objekter kan allokeres 3 steder i C++:
* globalt (static allocated)
* på stakken (automatic allocated)
* på heapen (dynamic allocated)
og det er kun den ene af de 3 som exit håndterer.
> >
> >Naturligvis er det C++ compileren der klarer det - automatisk,
> >velspecificeret og på et fornuftigt tidspunkt.
>
> Det begynder efterhånden at blive lidt for VB-agtigt for min smag.
Det er da i orden at du syntes det.
Men årsagen til din smag, eller præcist hvad du syntes der er VB-agtigt kan
jeg ikke se.
Det som jeg kan se af denne tråd er:
* Du bryder dig ikke om MS-Windows
* Du bryder dig ikke om C++
* Du bryder dig ikke om exception - uden du dog tilsyneladende kender
særligt meget til exceptions, eller har baseret det på erfaring
* Du ønsker ikke at sætte dig ind i hvad exception er, så du har en bedre
baggrund for at udtale dig
Blot for at fortælle hvorfor jeg har tænkt at stoppe i denne tråd.
> >
> >> oprydningen. Den burde compileren sørge for bliver kaldt ved exit(). I
> >
> >Nej - længe før programmet terminerer.
> >Nemlig når objektet går ud af scope - for objekter på stakken (automatic
> >allocated).
> >Man bør undgå at "hoppe sidelæns" ud af C++ ved hjælp af exit.
> >Istedet bør man køre "pænt" tilbage på kaldestakken, for derefter at
> >returnere almindeligt fra main.
>
> Det gør da bare C++ endnu mere "underligt"[1].
C har det på samme måde, hvis man ønsker at give den kaldende kode en chance
for at rydde op, så man kan fortsætte eksekveringen.
Man returnerer en fejlkode, som den kaldende kode håndterer passende. Sådan
kører man op af kalde stakken indtil man når til et stabilt punkt, hvor man
kan leve med den indtrådte fejl.
>
> >> C bør man bruge atexit() til den slags oprydning.
> >
> >Hvad hvis man ikke vil slutte (f.eks. en 24x7 server) - men prøve at
> >korrigere fejlsituationen, eller blot afvise at udføre den ønskede
handling
> >?
>
> Så har man nok slet ikke lyst til at miste fx. sin databaseforbindelse.
Nej, men man vil sikkert gerne nedlægge den database transaction som
fejlede - altså ryde pænt op og fortsætte.
Venlig hilsen
Mogens Hansen
| |
Kent Friis (09-05-2001)
| Kommentar Fra : Kent Friis |
Dato : 09-05-01 17:59 |
|
Den Wed, 9 May 2001 15:20:54 +0200 skrev Mogens Hansen:
>
>"Kent Friis" <kfr@fleggaard.dk> wrote in message
>news:9d9mef$jgl$1@sunsite.dk...
>>
>> Så er vi også ovre i at exception-delen fylder mere end kodedelen.
>
>Måske - måske ikke.
>Det er ikke ualmindeligt at fejlhåndtering fylder en væsentlig del af et
>stabilt program.
>Er der noget forkert i det ?
Det var den samme fejlhåndtering, som tilføjer måske to linier med
if-udgaven.
>> I ikke-objektorienterede sprog er det kun data der ligger på stakken,
>> og det vil ikke ændre på fx. forbindelsen til en database. Og uanset
>> om det er OO eller ej, så vil return eller exit sørge for at
>> destructoren bliver kaldt, så jeg kan egentlig ikke se det gør den
>> helt store forskel.
>
>Det er ikke rigtigt for C++ (og heller ikke for Java og C# - for der er ikke
>nogen destructor).
>
>Ved exit bliver destructorer til alle _globale_ objekter (static allocated)
>kaldt, men destructoren bliver ikke kaldt for objekter på stakken (automatic
>allocated).
Yikes - godt jeg ikke programmerer de sprog...
>Objekter kan allokeres 3 steder i C++:
> * globalt (static allocated)
> * på stakken (automatic allocated)
> * på heapen (dynamic allocated)
>og det er kun den ene af de 3 som exit håndterer.
I et fornuftigt designet sprog bør de to første blive håndteret
automatisk ved exit.
>> >Naturligvis er det C++ compileren der klarer det - automatisk,
>> >velspecificeret og på et fornuftigt tidspunkt.
>>
>> Det begynder efterhånden at blive lidt for VB-agtigt for min smag.
>
>Det er da i orden at du syntes det.
>Men årsagen til din smag, eller præcist hvad du syntes der er VB-agtigt kan
>jeg ikke se.
>Det som jeg kan se af denne tråd er:
> * Du bryder dig ikke om MS-Windows
Velbegrundet.
> * Du bryder dig ikke om C++
Det har måske indflydelse, at jeg har haft en lærer, som troede C++
var det samme som C med objekter.
>Blot for at fortælle hvorfor jeg har tænkt at stoppe i denne tråd.
Måske fornuftigt - jeg har da lært lidt af den, men ikke kun positivt!
>> >> oprydningen. Den burde compileren sørge for bliver kaldt ved exit(). I
>> >
>> >Nej - længe før programmet terminerer.
>> >Nemlig når objektet går ud af scope - for objekter på stakken (automatic
>> >allocated).
>> >Man bør undgå at "hoppe sidelæns" ud af C++ ved hjælp af exit.
>> >Istedet bør man køre "pænt" tilbage på kaldestakken, for derefter at
>> >returnere almindeligt fra main.
>>
>> Det gør da bare C++ endnu mere "underligt"[1].
>
>C har det på samme måde, hvis man ønsker at give den kaldende kode en chance
>for at rydde op, så man kan fortsætte eksekveringen.
C har ikke destructors, som skulle klare det hele automatisk. Så der
giver det mening, at de ikke bliver kaldt.
>> >Hvad hvis man ikke vil slutte (f.eks. en 24x7 server) - men prøve at
>> >korrigere fejlsituationen, eller blot afvise at udføre den ønskede
>handling
>> >?
>>
>> Så har man nok slet ikke lyst til at miste fx. sin databaseforbindelse.
>
>Nej, men man vil sikkert gerne nedlægge den database transaction som
>fejlede - altså ryde pænt op og fortsætte.
Så gør man det - jeg kan ikke se problemet.
Mvh
Kent
--
http://www.celebrityshine.com/~kfr/ - nu med Elgo-billeder
| |
Stephan Henningsen (04-05-2001)
| Kommentar Fra : Stephan Henningsen |
Dato : 04-05-01 18:21 |
|
On Thu, 3 May 2001 17:18:40 +0000 (UTC), Kent Friis wrote:
>Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
>>
>> * fejlhåndteringen blivere nemmere at implementere og teste, fordi det
>>ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot _at_
>>der er opstået en fejl.
>
>aka. "Generel fejl", som det er kendt fra de fleste windows-programmer.
aka catch ( unexpected ex ) { .. } ?
--
Stephan Henningsen /
/ http://tisprut.dk
| |
Mogens Hansen (05-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 05-05-01 06:58 |
|
Hej Stephan,
"Stephan Henningsen" <stephan@levelout.tisprut.dk> wrote in message
news:slrn9f5p6v.f7.stephan@levelout.tisprut.dk...
> On Thu, 3 May 2001 17:18:40 +0000 (UTC), Kent Friis wrote:
> >Den Thu, 3 May 2001 17:49:30 +0200 skrev Mogens Hansen:
> >>
> >> * fejlhåndteringen blivere nemmere at implementere og teste, fordi det
> >>ofte ikke er væsentlgt _hvilken_ fejl der er opstået, men derimod blot
_at_
> >>der er opstået en fejl.
> >
> >aka. "Generel fejl", som det er kendt fra de fleste windows-programmer.
>
> aka catch ( unexpected ex ) { .. } ?
Nej, se mit tidligere indlæg.
Hvis man vil (og har en Windows specifik compiler der understøtterdet -
f.eks. Microsoft Visual C++ eller Borland C++Builder) kan man skrive:
#include "stdio.h"
void main()
{
int* p = 0x00000000; // pointer to NULL
puts("hello");
try{
puts("in try");
try{
puts("in try");
*p = 13; // causes an access violation exception;
}__finally{
puts("in finally");
}
}__except(puts("in filter"), 1){
puts("in except");
}
puts("world");
}
Venig hilsen
Mogens Hansen
| |
Igor V. Rafienko (03-05-2001)
| Kommentar Fra : Igor V. Rafienko |
Dato : 03-05-01 18:20 |
|
* Mogens Hansen
> Fordelene ved exceptions er:
> * at man ikke kan undlade at håndtere fejlsituationer
Kunne du utdype litegrann? Man kan da gi blaffen i feilhåndtering
(bare anta at exception ikke forekommer og kjøre på; kompilatoren
tvinger ikke en til å håndtere exceptions (i motsetning til fx.
Java)).
[snip]
ivr
--
Documentation is like sex: when it is good, it is very, very good; and
when it is bad, it is better than nothing."
| |
Mogens Hansen (03-05-2001)
| Kommentar Fra : Mogens Hansen |
Dato : 03-05-01 20:49 |
|
Hej Igor,
"Igor V. Rafienko" <igorr@ifi.uio.no> wrote in message
news:xjvhez2ic2w.fsf@hel.ifi.uio.no...
> * Mogens Hansen
>
> > Fordelene ved exceptions er:
> > * at man ikke kan undlade at håndtere fejlsituationer
>
>
> Kunne du utdype litegrann? Man kan da gi blaffen i feilhåndtering
> (bare anta at exception ikke forekommer og kjøre på; kompilatoren
> tvinger ikke en til å håndtere exceptions (i motsetning til fx.
> Java)).
>
Jeg tror at jeg er med på hvad du mener.
Ved et foredrag, som Bjarne Stroustrup holdte i februar sidste år i
København, spurgte jeg ham netop om hvorfor C++ ikke håndhæver throw
specifikationer ligeså konsekvent som Java.
Jeg opfattede hans svar således at en håndhævelse af præcise throw
specifikationer ville blive et vedligeholdelses nighmare. Det væsentlige er
om der kan blive smidt en exception eller ej.
Jeg er enig med Bjarne Stroustrup, efter at have arbejdet intensivt med
brugen af exception det sidste 1½ år.
Hvis der bliver smidt en C++ exception, så sker der _noget_ - som er
veldefineret. Hvis man ikke selv gør noget ved en exception, så gør
implementationen noget.
Hvis man returnerer en fejlkode, sker der ikke nødvendigvis noget, og man
kan fortsætte eksekveringssekvensen, hvilke kan føre til "undefined
behaviour". F.eks. forsætte som om et kald til malloc gik godt, selv om det
faktisk fejlede.
Følgende signaturer:
T foo(...);
betyder at der kan komme en exception, men man kan ikke sige noget om typen.
T foo(...) throw ();
betyder at der ikke kan komme exceptions ud af funktionen.
Det er en _meget_ vigtig garanti i forbindelse med håndtering af exception,
at der er funktioner som ikke smider exceptions. "swap" funktionen på
container klasserne er et vigtigt eksempel, ogdestructorer bør _aldrig_
smide exceptions.
Hvis funktionen ikke opfylder hvad den lover, men gør noget som kaster en
exception uden at håndtere den, vil "unexpected" blive kaldt af
implementationen.
T foo(...) throw (X1, X2);
betyder at _kun_ exceptions af typerne X1 og X2 (og exceptions nedarvet fra
disse) kan komme ud af funktionen. Hvis andre prøver at komme ud, vil
"unexpected" blive kald af implementationen.
Hvis der bliver smidt en exception, der ikke bliver catch'et bliver
std::terminate kald.
Det er nok ikke helt præcist som jeg skrev "at man ikke kan undlade at
håndtere fejlsituationer". Det er nok mere præcist at sige noget i retningen
af "at man kan ikke fortsætte eksekveringssekvensen upåvirket af
fejlsituationen".
Venlig hilsen
Mogens Hansen
| |
|
|