/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
Bech_bb 500
kyllekylle 500
jdjespers.. 500
gibson 300
scootergr.. 300
molokyle 287
10  strarup 270
Fordel ved template argument for arraystør~
Fra : Janus


Dato : 09-05-07 16:53

hvad er fordelen ved at bruge en template til at angive en arrays størrelse
i en klasse?
Eksemplerne er

template:
template<int size>
class container {
float data[size];
.....

non template:
class container {
public:
container(int size)
{
data=new float[size];
}
float* data;
......


Jo, templateudgaven smider ens array sammen med resten af klassens data,
hvor den anden udgave putter den et andet sted på heap, men... hvad skulle
ellers være fordelen ved det? Læser lige nu "c++ templates: the complete
guide", hvor eksemplet bruges, men forfateren kommer ikke rigtig ind på
hvorfor dælen jeg skulle ønske at gøre det sådan.



 
 
Kent Friis (09-05-2007)
Kommentar
Fra : Kent Friis


Dato : 09-05-07 17:01

Den Wed, 9 May 2007 17:52:44 +0200 skrev Janus:
> hvad er fordelen ved at bruge en template til at angive en arrays størrelse
> i en klasse?
> Eksemplerne er
>
> template:
> template<int size>
> class container {
> float data[size];
> ....
>
> non template:
> class container {
> public:
> container(int size)
> {
> data=new float[size];
> }
> float* data;
> .....

Det første jeg bemærker er at man med template-udgaven ikke behøver
bekymre sig om pointere, new, delete og alle de fejl det kan give.

Mvh
Kent
--
"So there I was surrounded by all these scary creatures
They were even scarier than what Microsoft call features"
- C64Mafia: Forbidden Forest (Don't Go Walking Slow).

Jakob Bøhm (09-05-2007)
Kommentar
Fra : Jakob Bøhm


Dato : 09-05-07 17:07

Janus wrote:
> hvad er fordelen ved at bruge en template til at angive en arrays størrelse
> i en klasse?
> Eksemplerne er
>
> template:
> template<int size>
> class container {
> float data[size];
> ....
>
> non template:
> class container {
> public:
> container(int size)
> {
> data=new float[size];
> }
> float* data;
> .....
>
>
> Jo, templateudgaven smider ens array sammen med resten af klassens data,
> hvor den anden udgave putter den et andet sted på heap, men... hvad skulle
> ellers være fordelen ved det? Læser lige nu "c++ templates: the complete
> guide", hvor eksemplet bruges, men forfateren kommer ikke rigtig ind på
> hvorfor dælen jeg skulle ønske at gøre det sådan.
>
>

1. Du får halvt så mange kald til heap manager (som godt kan være lidt
langsom).

2. Hvis klassens inline metoder laver range-check på de array-indices
der kommer ind som argumenter kan disse checks ofte optimeres væk hvis
det kan eftervises statisk at index er inden for arrayets størrelse.

3. Hver gang du skal have fat i arrayet sparer du en RAM-adgang til en
anden cache-bucket end der hvor array-elementet ligger (du sparer nemlig
at læse pegeren fra der hvor klasse-instancen selv ligger og roder).
Dette kan give bedre udnyttelse af processorens cache.

4. Hvis du ikke har for mange forskellige template-instantieringer
bliver den samlede kodestørrelse forhåbentlig mindre da du udover en
mindre constructor og destructor også sparer al den kode som skal hente
pegeren til data og så derefere den.

5. Hvis arrayet ikke er det eneste indhold i klassen har du den klare
fordel at du overhovedet KAN erklære data som et almindeligt array.
Størrelsen på et erklæret array skal nemlig næsten altid være en
compile-time konstant, hvilket template-argumenter er, men
constructor-argumenter ikke er.


--
Jakob Bøhm, M.Sc.Eng. * jb@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax tel:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right

Janus (10-05-2007)
Kommentar
Fra : Janus


Dato : 10-05-07 13:20

>1. Du får halvt så mange kald til heap manager (som godt kan være lidt
>langsom).

Det er vel kun vec construction af objektet?

>2. Hvis klassens inline metoder laver range-check på de array-indices der
>kommer ind som argumenter kan disse checks ofte optimeres væk hvis det kan
>eftervises statisk at index er inden for arrayets størrelse.

Det troede jeg da aldrig skete i c++? Det er snart længe siden jeg var på
c++ sidst, så måske jeg husker forkert?

>3. Hver gang du skal have fat i arrayet sparer du en RAM-adgang til en
>anden cache-bucket end der hvor array-elementet ligger (du sparer nemlig at
>læse pegeren fra der hvor klasse-instancen selv ligger og roder). Dette kan
>give bedre udnyttelse af processorens cache.

Ja, det er nok en ret god pointe! Det burde være grund nok i sig selv




Jakob Bøhm (10-05-2007)
Kommentar
Fra : Jakob Bøhm


Dato : 10-05-07 13:44

Janus wrote:
>> 1. Du får halvt så mange kald til heap manager (som godt kan være lidt
>> langsom).
>
> Det er vel kun vec construction af objektet?
>
>> 2. Hvis klassens inline metoder laver range-check på de array-indices der
>> kommer ind som argumenter kan disse checks ofte optimeres væk hvis det kan
>> eftervises statisk at index er inden for arrayets størrelse.
>
> Det troede jeg da aldrig skete i c++? Det er snart længe siden jeg var på
> c++ sidst, så måske jeg husker forkert?
>

C++ laver som udgangspunkt ikke IMPLICITTE range-checks som de kendes
fra Pascal. Men gode C++ klasser indeholder explicitte if-sætninger som
validerer de fleste argumenter til metoderne, f.eks.

inline int SMPLCLASS<int cnt>:erator[](size_t i) {
if (i < cnt) return data[i]; else return 0;
}

int OTHRCLS<int cnt1>::Get(size_t i) {
if (i <= cnt1 && i > 0)
return smplObj[i - 1] + otherObj[i - 1];
else
return -1;
}


Hvis cnt er kendt compiletime (som her) kan if-sætningen i operator []
merges med if-sætningen i Get() og elimineres (hvis OTHRCLS<int
cnt>::smplObj er erklæret med en værdi af cnt som er >= cnt1).


--
Jakob Bøhm, M.Sc.Eng. * jb@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax tel:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right

Janus (10-05-2007)
Kommentar
Fra : Janus


Dato : 10-05-07 16:03

>Hvis cnt er kendt compiletime (som her) kan if-sætningen i operator []
>merges med if-sætningen i Get() og elimineres (hvis OTHRCLS<int
>cnt>::smplObj er erklæret med en værdi af cnt som er >= cnt1).

Fikst. Ja, gode metoder tester.. og nogle gør ikke. Har gennem tiden flere
gange lavet kode som ikke er sikker, men som er lidt hurtigere. Range check
er et typisk eksempel. At man så kan få i pose og sæk med templates, det er
jo smart.



Thorsten Ottosen (10-05-2007)
Kommentar
Fra : Thorsten Ottosen


Dato : 10-05-07 17:24

Jakob Bøhm skrev:

> C++ laver som udgangspunkt ikke IMPLICITTE range-checks som de kendes
> fra Pascal. Men gode C++ klasser indeholder explicitte if-sætninger som
> validerer de fleste argumenter til metoderne, f.eks.
>
> inline int SMPLCLASS<int cnt>:erator[](size_t i) {
> if (i < cnt) return data[i]; else return 0;
> }

Dette er absolut ikke et kendetegn for "gode" c++ klasser. Implmenter
istedet functionen som

inline int SMPLCLASS<int cnt>:erator[](size_t i)
{
assert( i < cnt );
return data[i];
}

out-of-bounds bør betragtes som en fejl af programmøren.

mvh

-Thorsten


Mogens Hansen (10-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 10-05-07 18:18


"Thorsten Ottosen" <thorsten.ottosen@dezide.com> wrote in message
news:4643472c$0$21930$157c6196@dreader1.cybercity.dk...

[8<8<8<]
> out-of-bounds bør betragtes som en fejl af programmøren.

Helt enig - det er et skråplan.
Som man siger: hvis man prøver at snyde sin compiler, skal den nok få sin
hævn

Tilmed er det en rigtig dårlig idee at returnere en værdi som er lovlig,
således at fejlsituationer ikke kan skelnes for normal operation.

--
Venlig hilsen

Mogens Hansen



Jakob Bøhm (11-05-2007)
Kommentar
Fra : Jakob Bøhm


Dato : 11-05-07 09:36

Mogens Hansen wrote:
> "Thorsten Ottosen" <thorsten.ottosen@dezide.com> wrote in message
> news:4643472c$0$21930$157c6196@dreader1.cybercity.dk...
>
> [8<8<8<]
>> out-of-bounds bør betragtes som en fejl af programmøren.
>
Men assert() er IKKE en sikker boundscheck, da assert() pr. definition
forsvinder i produktionsbuilds uanset om der stadig er noget i koden som
kan levere out-of-bounds indices.

Et andet problem er at out-of-bounds også kan være en fejl i input,
måske endog remote input, og så er en "assertion failure in line xxx in
foobar.cpp" ikke en særligt hensigtsmæssig reaktion. assert() og
throw() er nemme metoder til debug, legetøjskode og kortlivede
processer, men hele error-is-termination princippet går hurtigt galt i
den virkelige verden.

> Helt enig - det er et skråplan.
> Som man siger: hvis man prøver at snyde sin compiler, skal den nok få sin
> hævn
>
> Tilmed er det en rigtig dårlig idee at returnere en værdi som er lovlig,
> således at fejlsituationer ikke kan skelnes for normal operation.
>

I koden her blev det antaget at klassen blev brugt et sted hvor de
valgte returværdier (0 for den ene klasse, -1 for den anden) signalerede
fejl og altså ikke var en "lovlig" værdi.

--
Jakob Bøhm, M.Sc.Eng. * jb@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax tel:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right

Thorsten Ottosen (11-05-2007)
Kommentar
Fra : Thorsten Ottosen


Dato : 11-05-07 10:13

Jakob Bøhm skrev:
> Mogens Hansen wrote:
>> "Thorsten Ottosen" <thorsten.ottosen@dezide.com> wrote in message
>> news:4643472c$0$21930$157c6196@dreader1.cybercity.dk...
>>
>> [8<8<8<]
>>> out-of-bounds bør betragtes som en fejl af programmøren.
>>
> Men assert() er IKKE en sikker boundscheck, da assert() pr. definition
> forsvinder i produktionsbuilds uanset om der stadig er noget i koden som
> kan levere out-of-bounds indices.

Man er nødt til at definiere korrektheden af en function. Man kan gøre
det på flere forskellige måder, men en simpel kontrakt for en function
som regelt er nemmere for brugere af functionen.

> Et andet problem er at out-of-bounds også kan være en fejl i input,

Vi snakker ikke om input her, men om en ganske specifik index operation.

> måske endog remote input, og så er en "assertion failure in line xxx in
> foobar.cpp" ikke en særligt hensigtsmæssig reaktion. assert() og
> throw() er nemme metoder til debug, legetøjskode og kortlivede
> processer, men hele error-is-termination princippet går hurtigt galt i
> den virkelige verden.

Jeg ved ikke hvilken verden du lever i, men i vores firma unit-tester og
regression tester vi en del. Vi bruger også assert() og lign. overalt i
koden til at tjekke pre og post-betingelser.
Alle programmørfejl fanges tidligt i udviklingsprocessen med assert()
eller lign..

>> Helt enig - det er et skråplan.
>> Som man siger: hvis man prøver at snyde sin compiler, skal den nok få
>> sin hævn
>>
>> Tilmed er det en rigtig dårlig idee at returnere en værdi som er
>> lovlig, således at fejlsituationer ikke kan skelnes for normal operation.
>>
>
> I koden her blev det antaget at klassen blev brugt et sted hvor de
> valgte returværdier (0 for den ene klasse, -1 for den anden) signalerede
> fejl og altså ikke var en "lovlig" værdi.

Det er muligt, men det åbner for at man kan glemme at tjekke
returværdien, og det vil i det lange løb føre til langsommere kode.

Denne artikkel kan anbefales:

http://www.artima.com/cppsource/deepspace.html

og det kan Wilson's bog "Imperfect C++" også.

-Thorsten




Arne Vajhøj (13-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 13-05-07 01:02

Thorsten Ottosen wrote:
> Jeg ved ikke hvilken verden du lever i, men i vores firma unit-tester og
> regression tester vi en del. Vi bruger også assert() og lign. overalt i
> koden til at tjekke pre og post-betingelser.
> Alle programmørfejl fanges tidligt i udviklingsprocessen med assert()
> eller lign..

I fanger *alle* programmørfejl.

Jeg er meget imponeret.

Arne

Mogens Hansen (13-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 13-05-07 11:14


"Arne Vajhøj" <arne@vajhoej.dk> wrote in message
news:46465566$0$90263$14726298@news.sunsite.dk...

[8<8<8<]
> I fanger *alle* programmørfejl.
>
> Jeg er meget imponeret.

Du har selvfølgelig ret.
Men det kan ikke bruges til så meget før du fortæller hvilken politik der er
bedre.

--
Venlig hilsen

Mogens Hansen



Arne Vajhøj (13-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 13-05-07 18:58

Mogens Hansen wrote:
> "Arne Vajhøj" <arne@vajhoej.dk> wrote in message
> news:46465566$0$90263$14726298@news.sunsite.dk...
>> I fanger *alle* programmørfejl.
>>
>> Jeg er meget imponeret.
>
> Du har selvfølgelig ret.
> Men det kan ikke bruges til så meget før du fortæller hvilken politik der er
> bedre.

Du har vist ikke forstået pointen.

Det vigtige er at man aldrig kan regne med at alle programmerings fejl
er fundet inden koden går i produktion. Og at det har nogle konsekvenser
for hvordan man bør håndtere fejl.

Om jeg kender en bedre process og om der overhovedet findes en bedre
process til at reducere antal fejl er ligegyldigt.

Arne


Thorsten Ottosen (13-05-2007)
Kommentar
Fra : Thorsten Ottosen


Dato : 13-05-07 19:37

Arne Vajhøj skrev:
> Thorsten Ottosen wrote:
>> Jeg ved ikke hvilken verden du lever i, men i vores firma unit-tester og
>> regression tester vi en del. Vi bruger også assert() og lign. overalt
>> i koden til at tjekke pre og post-betingelser.
>> Alle programmørfejl fanges tidligt i udviklingsprocessen med assert()
>> eller lign..
>
> I fanger *alle* programmørfejl.
>
> Jeg er meget imponeret.

Det afhænger vel af din definition af "programmørfejl." Lad være med at
læse det som fanden læser bibelen.

-Thorsten

Mogens Hansen (13-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 13-05-07 20:12


"Thorsten Ottosen" <thorsten.ottosen@dezide.com> wrote in message
news:46475ad8$0$7612$157c6196@dreader2.cybercity.dk...
> Arne Vajhøj skrev:
>> Thorsten Ottosen wrote:
>>> Jeg ved ikke hvilken verden du lever i, men i vores firma unit-tester og
>>> regression tester vi en del. Vi bruger også assert() og lign. overalt i
>>> koden til at tjekke pre og post-betingelser.
>>> Alle programmørfejl fanges tidligt i udviklingsprocessen med assert()
>>> eller lign..
>>
>> I fanger *alle* programmørfejl.
>>
>> Jeg er meget imponeret.
>
> Det afhænger vel af din definition af "programmørfejl." Lad være med at
> læse det som fanden læser bibelen.

Min erfaring er at spørgsmålet om korrekthed af kode og test i _meget_ høj
grad er et spørgsmål om holdning.
F.eks. er brugen af assert og dynamiske analysatorer, så man ikke kan overse
f.eks. out-of-bounds tilgang, meget væsentlige.

Det betyder ikke at man kan lave store, fejlfrie - men det bliver væsentlige
nemmere.

--
Venlig hilsen

Mogens Hansen



Thorsten Ottosen (14-05-2007)
Kommentar
Fra : Thorsten Ottosen


Dato : 14-05-07 10:32

Mogens Hansen skrev:
> "Thorsten Ottosen" <thorsten.ottosen@dezide.com> wrote in message
> news:46475ad8$0$7612$157c6196@dreader2.cybercity.dk...
>> Arne Vajh�j skrev:
>>> Thorsten Ottosen wrote:
>>>> Jeg ved ikke hvilken verden du lever i, men i vores firma unit-tester og
>>>> regression tester vi en del. Vi bruger ogs� assert() og lign. overalt i
>>>> koden til at tjekke pre og post-betingelser.
>>>> Alle programm�rfejl fanges tidligt i udviklingsprocessen med assert()
>>>> eller lign..
>>> I fanger *alle* programm�rfejl.
>>>
>>> Jeg er meget imponeret.
>> Det afh�nger vel af din definition af "programm�rfejl." Lad v�re med at
>> l�se det som fanden l�ser bibelen.
>
> Min erfaring er at sp�rgsm�let om korrekthed af kode og test i _meget_ h�j
> grad er et sp�rgsm�l om holdning.
> F.eks. er brugen af assert og dynamiske analysatorer, s� man ikke kan overse
> f.eks. out-of-bounds tilgang, meget v�sentlige.
>
> Det betyder ikke at man kan lave store, fejlfrie - men det bliver v�sentlige
> nemmere.

Jeg manglede et tillægsords efter "alle".

Man fanger alle *simple* programmeringsfejl.

beklager misforståelsen.

-Thorsten

Arne Vajhøj (18-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 18-05-07 01:20

Thorsten Ottosen wrote:
> Jeg manglede et tillægsords efter "alle".
>
> Man fanger alle *simple* programmeringsfejl.
>
> beklager misforståelsen.



Arne

Mogens Hansen (11-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 11-05-07 16:08


"Jakob Bøhm" <jb@danware.dk> wrote in message
news:46442aed$0$13950$edfadb0f@dread15.news.tele.dk...

> Mogens Hansen wrote:
> > "Thorsten Ottosen" <thorsten.otto...@dezide.com> wrote in message
> > news:4643472c$0$21930$157c6196@dreader1.cybercity.dk...
>
> > [8<8<8<]
> >> out-of-bounds bør betragtes som en fejl af programmøren.
>
> Men assert() er IKKE en sikker boundscheck, da assert() pr. definition
> forsvinder i produktionsbuilds uanset om der stadig er noget i koden som
> kan levere out-of-bounds indices.

Det har du fuldstændig ret i.

Men det rejser det helt fundamentale problem, hvis vi er enige om at
out-of-bounds er en software fejl:
Hvordan kommer programmet sikkert, og fornuftigt videre fra en tilstand der
aldrig var forudset ?
Det eneste rimelige svar er at bringe programmet til en garanteret kendt og
lovlig tilstand - hvilket i praksis nemmest betyder afslut programmet
hurtigst muligt!

Man må som programmør overveje om man bruger et bounds-checked interface
eller ej, og forholde sig til det.
Det er derfor std::vector både har "operator []" og "at", hvor den sidste er
range-checket.

>
> Et andet problem er at out-of-bounds også kan være en fejl i input,
> måske endog remote input, og så er en "assertion failure in line xxx in
> foobar.cpp" ikke en særligt hensigtsmæssig reaktion. assert() og
> throw() er nemme metoder til debug, legetøjskode og kortlivede
> processer, men hele error-is-termination princippet går hurtigt galt i
> den virkelige verden.

Fejlbehæftet kode går hurtigt galt i den virkelige verden.
Hvis programmet kommer i en ukendt tilstand giver det ingen mening af
forsætte.

Man må sikre sig at man overholder sine forpligtigelser inden man kalder et
givent interface. Det er uanset om interfacet er range-checked eller ej.

[8<8<8<]
> I koden her blev det antaget at klassen blev brugt et sted hvor de
> valgte returværdier (0 for den ene klasse, -1 for den anden) signalerede
> fejl og altså ikke var en "lovlig" værdi.

Eksemplet var en container med tal, hvor værdien 0 bestemt vil kunne
indeholdes i containeren.
Det giver _ingen_ mening at returnere 0 som fejlkode i det eksempel.

--
Venlig hilsen

Mogens Hansen



Arne Vajhøj (13-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 13-05-07 01:05

Mogens Hansen wrote:
> Men det rejser det helt fundamentale problem, hvis vi er enige om at
> out-of-bounds er en software fejl:
> Hvordan kommer programmet sikkert, og fornuftigt videre fra en tilstand der
> aldrig var forudset ?
> Det eneste rimelige svar er at bringe programmet til en garanteret kendt og
> lovlig tilstand - hvilket i praksis nemmest betyder afslut programmet
> hurtigst muligt!

Det er uden tvivl det nemmeste.

Men det er ikke nødvendigvis hensigtsmæssigt i konteksten.

Hvis det havde været den universelle løsning, så kunne et pålideligt
shutdown hook havde erstattet exception mekanismen.

Arne

Mogens Hansen (13-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 13-05-07 11:19


"Arne Vajhøj" <arne@vajhoej.dk> wrote in message
news:46465618$0$90263$14726298@news.sunsite.dk...

[8<8<8<]
> Hvis det havde været den universelle løsning, så kunne et pålideligt
> shutdown hook havde erstattet exception mekanismen.

Nej - absolut ikke.
Exceptions er en udemærket måde at håndtere forudsete fejl (f.eks. disken
løber fuld, netværksforbindelse forsvandt, input data er ugyldige).
Problemet opstår man snakker om uforudsete fejl, som brug af et interface
uden for dets specifikation.

Det skete i den første Arianne 5 raket.
Her var forudsætningen også at softwaren var fejlfri, men systemet var
robust overfor hardware fejl.
Da det så viste sig at forudsætningen ikke holdt, var der ikke andet end den
store, dyre stopknap der virkede (raketten knækkede også pga. af fejlen, og
ville være gået tabt under alle omstændigheder)

--
Venlig hilsen

Mogens Hansen



Arne Vajhøj (13-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 13-05-07 19:02

Mogens Hansen wrote:
> "Arne Vajhøj" <arne@vajhoej.dk> wrote in message
> news:46465618$0$90263$14726298@news.sunsite.dk...
>> Hvis det havde været den universelle løsning, så kunne et pålideligt
>> shutdown hook havde erstattet exception mekanismen.
>
> Nej - absolut ikke.
> Exceptions er en udemærket måde at håndtere forudsete fejl (f.eks. disken
> løber fuld, netværksforbindelse forsvandt, input data er ugyldige).
> Problemet opstår man snakker om uforudsete fejl, som brug af et interface
> uden for dets specifikation.

Du antager at forudset=>recoverable og uforudset=>ikke recoverable.

Det tror jeg ikke altid vil være tilfældet.

Arne

Mogens Hansen (14-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 14-05-07 19:44


"Arne Vajhøj" <arne@vajhoej.dk> wrote in message
news:46475292$0$90271$14726298@news.sunsite.dk...

[8<8<8<]
> Du antager at forudset=>recoverable og uforudset=>ikke recoverable.
>
> Det tror jeg ikke altid vil være tilfældet.

Forudsete fejl er ikke altid recoverable - men man har muligheden for at
lade systemet håndtere situationen på en bevidst måde.
Forudsete fejl kan i sagens natur ikke forudsiges hvordan de udarter sig -
hvordan skulle man kunne det ?

--
Venlig hilsen

Mogens Hansen



Arne Vajhøj (18-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 18-05-07 01:23

Mogens Hansen wrote:
> "Arne Vajhøj" <arne@vajhoej.dk> wrote in message
> news:46475292$0$90271$14726298@news.sunsite.dk...
>> Du antager at forudset=>recoverable og uforudset=>ikke recoverable.
>>
>> Det tror jeg ikke altid vil være tilfældet.
>
> Forudsete fejl er ikke altid recoverable - men man har muligheden for at
> lade systemet håndtere situationen på en bevidst måde.
> Forudsete fejl kan i sagens natur ikke forudsiges hvordan de udarter sig -
> hvordan skulle man kunne det ?

Uforudsete fejl kan ikke forudses, men det betyder ikke per automatik
at de ikke kan recoveres eller at det ikke er en fordel at forsøge at
recovere.

Arne

Arne Vajhøj (13-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 13-05-07 01:00

Jakob Bøhm wrote:
> Et andet problem er at out-of-bounds også kan være en fejl i input,
> måske endog remote input, og så er en "assertion failure in line xxx in
> foobar.cpp" ikke en særligt hensigtsmæssig reaktion. assert() og
> throw() er nemme metoder til debug, legetøjskode og kortlivede
> processer, men hele error-is-termination princippet går hurtigt galt i
> den virkelige verden.

Throwing exceptions er ikke nødvendigvis error-is-termination.

Arne

Jakob Bøhm (14-05-2007)
Kommentar
Fra : Jakob Bøhm


Dato : 14-05-07 12:24

Arne Vajhøj wrote:
> Jakob Bøhm wrote:
>> Et andet problem er at out-of-bounds også kan være en fejl i input,
>> måske endog remote input, og så er en "assertion failure in line xxx
>> in foobar.cpp" ikke en særligt hensigtsmæssig reaktion. assert() og
>> throw() er nemme metoder til debug, legetøjskode og kortlivede
>> processer, men hele error-is-termination princippet går hurtigt galt i
>> den virkelige verden.
>
> Throwing exceptions er ikke nødvendigvis error-is-termination.
>
Hele exceptions-mekanismen er i sit grunddesign en "dæmpet" udgaver af
error-is-termination, hvor man kan stoppe termineringen med en finere
granularitet end en hel process. Næsten alle andre egenskaber ved
error-is-termination er der stadig: Al data som ligger i
funktionsstakken mellem throw() og den relevante catch() tabes eller
rulles tilbage med generiske ufleksible mekanismer. Et stykke lineær
kode mister egenskaben at linierne udføres allesammen eller slet ikke.
Al robust kode skal lave paranoide data-commits i tide og utide for
"hvad nu hvis jeg pludselig bliver slået ihjel". Der er en høj
real-world risiko for datatab. Vi har nok alle oplevet at bande over en
editor som pludselig terminerede før vi havde savet vores seneste guldkorn.

I andre posts er mit forslag kritiseret ud fra antagelser om at alle
dårlige index er programmeringsfejl, eller at det ikke er meningen at
returnering af en fejlværdi skal detekteres/håndteres af kalderen.
Udgangspunktet for mine eksempler er det alternative princip at
funktioner som meningsfuldt kan fejle bør returnere en eksplicit
angivelse af success/fejl, som kalderen så kan/bør teste på. Denne
angivelse kan være en separat returparameter som det kendes fra f.eks.
Microsoft COM (alting returnerer HRESULT, semantiske returværdier
anbringes i referenceargumenter) eller det kan være en veldefineret
out-of-range værdi for den normale returparameter som det kendes fra
f.eks. traditionelle C API-er som fopen() og fgetch(). Den sidstnævnte
løsning er især praktisk hvis man samtidig laver en designregel om at
sådanne fejlværdier propageres som fejlværdier overalt, ligesom det
kendes fra IEEE NaNs etc. Hvis man for eksempel propagere -1 som indeks
til et nyt opslag i en funktion med rangecheck, så får man igen en
fejlreturværdi o.s.v. At en funktion returnerer den rette
fejlindikering ved ugyldigt input er naturligvis en del af den kontrakt
som skal testes med unit-tests.

En anden fejlantagelse i nogle svar er at range-check kun er en
debugging-mekanisme som i et "fejlfrit" program kan disables i
produktionskoden. Range-check har også et helt andet formål, nemlig at
gøre programmer robuste i tilfælde af at det lykkes nogen at smugle en
ugyldig værdi forbi inputfiltrene.

En tredje fejlantagelse er at det ikke er spor slemt at lukke et program
ned ved fejl. Det kommer meget an på programmet og må derfor ikke
dikteres af generelle klassebiblioteker. Nogen programmer (f.eks.
Webservere) skal bare køre 24x7, og en halvdårlig kørsel er bedre end
slet ingen kørsel. Andre programmer skal alligevel kun køre et øjeblik
(f.eks. en C++-compiler), og det er helt i orden at funktionsbiblioteker
sprænger sig selv og processen i luften for at forhindre at der
kompileres til et program som ikke matcher sourcekoden.

Fejlhåndtering er svært. Der er ingen perfekte universalløsninger.


--
Jakob Bøhm, M.Sc.Eng. * jb@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax tel:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right

Thorsten Ottosen (14-05-2007)
Kommentar
Fra : Thorsten Ottosen


Dato : 14-05-07 13:31

Jakob Bøhm skrev:

> I andre posts er mit forslag kritiseret ud fra antagelser om at alle
> dårlige index er programmeringsfejl, eller at det ikke er meningen at
> returnering af en fejlværdi skal detekteres/håndteres af kalderen.

Jeg sagde, at man risikerer at fejlværdien ikke tjekkes.

> Udgangspunktet for mine eksempler er det alternative princip at
> funktioner som meningsfuldt kan fejle bør returnere en eksplicit
> angivelse af success/fejl, som kalderen så kan/bør teste på.

Right. Og eksemplet var helt forfejlet i den henseende.

> Denne
> angivelse kan være en separat returparameter som det kendes fra f.eks.
> Microsoft COM (alting returnerer HRESULT, semantiske returværdier
> anbringes i referenceargumenter) eller det kan være en veldefineret
> out-of-range værdi for den normale returparameter som det kendes fra
> f.eks. traditionelle C API-er som fopen() og fgetch().

Både COM og mange C API-er er exempler på API'er som er extremt svære
at bruge korrekt. Hvis disse exempler indikerer noget, så er det vel
nærmest at return værdier er noget møj.

> Den sidstnævnte
> løsning er især praktisk hvis man samtidig laver en designregel om at
> sådanne fejlværdier propageres som fejlværdier overalt, ligesom det
> kendes fra IEEE NaNs etc. Hvis man for eksempel propagere -1 som indeks
> til et nyt opslag i en funktion med rangecheck, så får man igen en
> fejlreturværdi o.s.v. At en funktion returnerer den rette
> fejlindikering ved ugyldigt input er naturligvis en del af den kontrakt
> som skal testes med unit-tests.

Koden ender med at drukne i håndtering af disse fejlværdier. Hvad nu
hvis functionen har brug for endnu en fejl-værdi? Det bedste metode til
håndtering af fejlkoder, som jeg kender, er at bruge en global fejl-kode
stak.

> En anden fejlantagelse i nogle svar er at range-check kun er en
> debugging-mekanisme som i et "fejlfrit" program kan disables i
> produktionskoden. Range-check har også et helt andet formål, nemlig at
> gøre programmer robuste i tilfælde af at det lykkes nogen at smugle en
> ugyldig værdi forbi inputfiltrene.

Hvad betyder robust? At det ikke crasher? Programmet har stadig gået i
en ulovlig tilstand, og du ved jo faktisk ikke at det skyldes
inputfiltrene eller noget helt andet.

> En tredje fejlantagelse er at det ikke er spor slemt at lukke et program
> ned ved fejl. Det kommer meget an på programmet og må derfor ikke
> dikteres af generelle klassebiblioteker.

Enig.

> Fejlhåndtering er svært. Der er ingen perfekte universalløsninger.

Enig, men der er visse løsninger som er bedre end andre.

-Thorsten

Jakob Bøhm (14-05-2007)
Kommentar
Fra : Jakob Bøhm


Dato : 14-05-07 14:16

Thorsten Ottosen wrote:
> Jakob Bøhm skrev:
>
>> I andre posts er mit forslag kritiseret ud fra antagelser om at alle
>> dårlige index er programmeringsfejl, eller at det ikke er meningen at
>> returnering af en fejlværdi skal detekteres/håndteres af kalderen.
>
> Jeg sagde, at man risikerer at fejlværdien ikke tjekkes.
Man risikerer også at exceptions ikke checkes.
>
>> Udgangspunktet for mine eksempler er det alternative princip at
>> funktioner som meningsfuldt kan fejle bør returnere en eksplicit
>> angivelse af success/fejl, som kalderen så kan/bør teste på.
>
> Right. Og eksemplet var helt forfejlet i den henseende.
Uenig under de angivne forudsætninger.
>
>> Denne angivelse kan være en separat returparameter som det kendes fra
>> f.eks. Microsoft COM (alting returnerer HRESULT, semantiske
>> returværdier anbringes i referenceargumenter) eller det kan være en
>> veldefineret out-of-range værdi for den normale returparameter som det
>> kendes fra f.eks. traditionelle C API-er som fopen() og fgetch().
>
> Både COM og mange C API-er er exempler på API'er som er extremt svære
> at bruge korrekt. Hvis disse exempler indikerer noget, så er det vel
> nærmest at return værdier er noget møj.

Rå COM-programmering uden maskinhjælp er ualmindeligt svært, ja.
De nævnte C-API-er er derimod ret lette at bruge korrekt (i modsætning
til visse beslægtede funktioner fra de samme biblioteker). Men nej,
disse eksempler indikerer IKKE at returværdier er noget møg.

>
>> Den sidstnævnte løsning er især praktisk hvis man samtidig laver en
>> designregel om at sådanne fejlværdier propageres som fejlværdier
>> overalt, ligesom det kendes fra IEEE NaNs etc. Hvis man for eksempel
>> propagere -1 som indeks til et nyt opslag i en funktion med
>> rangecheck, så får man igen en fejlreturværdi o.s.v. At en funktion
>> returnerer den rette fejlindikering ved ugyldigt input er naturligvis
>> en del af den kontrakt som skal testes med unit-tests.
>
> Koden ender med at drukne i håndtering af disse fejlværdier. Hvad nu
> hvis functionen har brug for endnu en fejl-værdi? Det bedste metode til
> håndtering af fejlkoder, som jeg kender, er at bruge en global fejl-kode
> stak.
>
En global fejlkodestak (pr. tråd) er et godt hjælpeværktøj til at skelne
forskellige fejl fra hinanden. Men en fejlkodestak er ofte uegnet til
at angive success/failure, som derfor normalt angives i en
success/failure returværdi eller via andre mekanismer udenfor
fejlkodestakken.

>> En anden fejlantagelse i nogle svar er at range-check kun er en
>> debugging-mekanisme som i et "fejlfrit" program kan disables i
>> produktionskoden. Range-check har også et helt andet formål, nemlig
>> at gøre programmer robuste i tilfælde af at det lykkes nogen at smugle
>> en ugyldig værdi forbi inputfiltrene.
>
> Hvad betyder robust? At det ikke crasher? Programmet har stadig gået i
> en ulovlig tilstand, og du ved jo faktisk ikke at det skyldes
> inputfiltrene eller noget helt andet.

Robust betyder her, som i andre ingeniørdiscipliner at en mindre fejl
ikke eskalerer til en katastrofe. Hvis nogen smadrer et vindue i et hus
må det ikke få huset til at styrte sammen. Hvis bilen punkterer er den
ikke totalskadet og kan stadig styres ind i nødsporet så man kan sætte
reservehjulet på. Og hvis der slipper ulovlige data ind i et program må
der ikke opstå et udnytbart sikkerhedshul, end ikke til DoS-angreb.

Nej, rangechecket har forhindret at der er opstået en ulovlig generel
tilstand, forudsat at den ugyldige værdi ikke har fået lov at lave anden
ballade først.

>
>> En tredje fejlantagelse er at det ikke er spor slemt at lukke et
>> program ned ved fejl. Det kommer meget an på programmet og må derfor
>> ikke dikteres af generelle klassebiblioteker.
>
> Enig.
>
>> Fejlhåndtering er svært. Der er ingen perfekte universalløsninger.
>
> Enig, men der er visse løsninger som er bedre end andre.
>
Ja, og in-band fejlindikering (korrekt udført) er en af de gode.


--
Jakob Bøhm, M.Sc.Eng. * jb@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax tel:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right

Thorsten Ottosen (14-05-2007)
Kommentar
Fra : Thorsten Ottosen


Dato : 14-05-07 17:04

Jakob Bøhm skrev:
> Thorsten Ottosen wrote:

>>> En anden fejlantagelse i nogle svar er at range-check kun er en
>>> debugging-mekanisme som i et "fejlfrit" program kan disables i
>>> produktionskoden. Range-check har også et helt andet formål, nemlig
>>> at gøre programmer robuste i tilfælde af at det lykkes nogen at
>>> smugle en ugyldig værdi forbi inputfiltrene.
>>
>> Hvad betyder robust? At det ikke crasher? Programmet har stadig gået i
>> en ulovlig tilstand, og du ved jo faktisk ikke at det skyldes
>> inputfiltrene eller noget helt andet.
>
> Robust betyder her, som i andre ingeniørdiscipliner at en mindre fejl
> ikke eskalerer til en katastrofe.

[snip]

> Nej, rangechecket har forhindret at der er opstået en ulovlig generel
> tilstand, forudsat at den ugyldige værdi ikke har fået lov at lave anden
> ballade først.

Du ved jo ikke om den ugyldige værdi skyldes en lille eller stor fejl.
Der er ingen måde hvorpå du kan vide det i det generelle tilfælde. Ingen.

Jeg vil igen opfordrer til at du læser

http://www.artima.com/cppsource/deepspace.html

-Thorsten

Mogens Hansen (14-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 14-05-07 20:41


"Jakob Bøhm" <jb@danware.dk> wrote in message
news:464860f8$0$13975$edfadb0f@dread15.news.tele.dk...

[8<8<8<]
> Robust betyder her, som i andre ingeniørdiscipliner at en mindre fejl ikke
> eskalerer til en katastrofe. Hvis nogen smadrer et vindue i et hus må det
> ikke få huset til at styrte sammen. Hvis bilen punkterer er den ikke
> totalskadet og kan stadig styres ind i nødsporet så man kan sætte
> reservehjulet på.

Jeg har været involveret i udvikling af systemer som skal være _meget_
robuste.
Det involverer analyse af fejl-scenarier, håndtering af disse, krav til hvad
man må og ikke må i software og redundant hardware.
Udefra kommende institutioner verificerer at systemet rent faktisk er robust
overfor fejl situationer som nedbrud af netværk, sensorer eller computere i
netværket.

--
Venlig hilsen

Mogens Hansen




Mogens Hansen (14-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 14-05-07 20:41

>
> "Jakob Bøhm" <jb@danware.dk> wrote in message
> news:464846b7$0$13937$edfadb0f@dread15.news.tele.dk...

[8<8<8<]
> Et stykke lineær kode mister egenskaben at linierne udføres allesammen
> eller slet ikke.

Der er ingen principiel forskel på fejlhåndtering med exceptions eller retur
koder.
Det er mere et spørgsmål om at separere fejlhåndterings koden fra "normal"
kode.

I yderste konsekvens kan man transformere fra exception til fejlkode og den
anden vej:
try {
func();
}
catch(...) {
return SOME_ERROR;
}

og

if(NO_ERRR != func()) {
throw runtime_error();
}

Hvis man modtager en fejlkode er det meget almindeligt at funktionen må
returnere, uden at eksekvere det normale flow. Prøv bare at kig på typisk
Microsoft COM kode.
Tilsvarende er det muligt at fortsætte eksekveringen, selvom der smides en
exception - det gør vi ofte i det program jeg primært udvikler på, og især i
brugerfladen.

> Al robust kode skal lave paranoide data-commits i tide og utide for "hvad
> nu hvis jeg pludselig bliver slået ihjel". Der er en høj real-world
> risiko for datatab.

Det har ikke noget med exceptions a gøre.


> Vi har nok alle oplevet at bande over en editor som pludselig terminerede
> før vi havde savet vores seneste guldkorn.

Helt klart.
Jeg husker een editor som fangede "general protection fejl" (altså en ikke
forudset fejl), og pænt spurge om man ville gemme filen alligevel.
Hvis man sagde ja, så slettede den hele filen!
Det er blot eet eksempel på at det er svært at komme ud af en ukendt
tilstand på en fornuftig måde.
Den kortsigtede løsning var _altid_ at svare nej. Den langsigtede løsning
var at forbedre stabiliteten.

[8<8<8<]
> En anden fejlantagelse i nogle svar er at range-check kun er en
> debugging-mekanisme som i et "fejlfrit" program kan disables i
> produktionskoden.

Hvorfor er range-check speciel ?
Tester du ved indgangen til enhver member-funktion at "this" pointeren er
gyldig ?
Hvis ikke: hvorfor ?
Under udvikling (debug build) checker jeg normalt _samtlige_ this-pointere,
_alle_ pointer operationer inklusiv range check etc. (det er et værktøj som
gør det).
Men i release build er det disablet, fordi programmet kører ca. 10 gange
langsommere.


[8<8<8<]
> En tredje fejlantagelse er at det ikke er spor slemt at lukke et program
> ned ved fejl.

Du fusker med citaterne !!!
Hvor i denne tråd har nogen sagt at det ikke er spor slemt ?

> Det kommer meget an på programmet og må derfor ikke dikteres af generelle
> klassebiblioteker.

Jeps
Men generelle biblioteker må gerne stille krav, som kalderen skal overholde
for at få den ønskede virkning.

> Nogen programmer (f.eks. Webservere) skal bare køre 24x7, og en halvdårlig
> kørsel er bedre end slet ingen kørsel.

Gælder det altid ?
Hvad hvis man udnytter en programmerings fejl i webserveren (eller en af de
applikation den kører) til at få kontrol over computeren ?

Hvis man kigger på en Webserver som Microsoft IIS, så har den forskellige
modeller for hvordan man kan eksekvere udvidelser (web applikationer).
Der er et trade-off mellem performance og pålidelighed.
Man kan konfigurere IIS således at selve serveren kører i een process og
hver udvidelse (f.eks. ASP applikation) kører i hver sin process.
Det betyder at man har operativ-systemet og hardware til at beskytte selve
serveren og udvidelserne fra hinanden, så en applikation der går amok ikke
kan slå IIS serveren ned.

Det er netop en løsning, hvor man i tilfælde af uforudsete fejl kan bringe
programmet (IIS) i en kendt tilstand.

Noget tilsvarende er argumentationen for micro-kernel operativ systemer.


--
Venlig hislen

Mogens Hansen



Jakob Bøhm (15-05-2007)
Kommentar
Fra : Jakob Bøhm


Dato : 15-05-07 09:02

Mogens Hansen wrote:
>> "Jakob Bøhm" <jb@danware.dk> wrote in message
>> news:464846b7$0$13937$edfadb0f@dread15.news.tele.dk...
>
> [8<8<8<]
>> Et stykke lineær kode mister egenskaben at linierne udføres allesammen
>> eller slet ikke.
>
> Der er ingen principiel forskel på fejlhåndtering med exceptions eller retur
> koder.
Bortset fra læselighed og overskuelighed.

> Det er mere et spørgsmål om at separere fejlhåndterings koden fra "normal"
> kode.
>
> I yderste konsekvens kan man transformere fra exception til fejlkode og den
> anden vej:
> try {
> func();
> }
> catch(...) {
> return SOME_ERROR;
> }
>
> og
>
> if(NO_ERRR != func()) {
> throw runtime_error();
> }
>
> Hvis man modtager en fejlkode er det meget almindeligt at funktionen må
> returnere, uden at eksekvere det normale flow. Prøv bare at kig på typisk
> Microsoft COM kode.

Enig. Der findes også COM-klassebiblioteker hvor alle kald til/fra
COM-interfaces automatisk converterer mellem fejlkoder og C++
exceptions. Microsoft's scriptsprog gør dette konsekvent som en del af
deres runtime.

> Tilsvarende er det muligt at fortsætte eksekveringen, selvom der smides en
> exception - det gør vi ofte i det program jeg primært udvikler på, og især i
> brugerfladen.
God ide.
>
>> Al robust kode skal lave paranoide data-commits i tide og utide for "hvad
>> nu hvis jeg pludselig bliver slået ihjel". Der er en høj real-world
>> risiko for datatab.
>
> Det har ikke noget med exceptions a gøre.

Tag følgende funktion (lavet med pointere i stedet for referencer for at
kunne lave en runtime check):

template<T> bool swap(T *pa, T *pb)
{
T x;
if (pa && pb) {
x = *pa;
*pa = *pb;
*pb = x;
return true;
}
return false;
}

Hvis T er en normal type kan man med sikkerhed regne med at funktionen
enten bytter om på a og b eller gør ingenting. Det er let at resonere
med hensyn til opretholdelse af invarianter m.m.

Hvis T er en klasse som kan throwe en exception (f.eks. xalloc) i sin
operator =, så kan man ikke længere antage noget som helst om
opretholdelse af invarianter, da man risikerer at blive efterladt med to
kopier af den ene værdi, men ingen af den anden. For at få en
forudsigelig og verificerbar semantik bliver man nødt til at tilføje en
masse try blokke eller bruge dummy-klasser til at simulere
__finally-blokke. Læremestre udi pure C++-thinking elsker at pille den
slags eksempler fra hinanden enkeltvis og så påstå de har modbevist
problemets eksistens i almindelighed.


>
>
>> Vi har nok alle oplevet at bande over en editor som pludselig terminerede
>> før vi havde savet vores seneste guldkorn.
>
> Helt klart.
> Jeg husker een editor som fangede "general protection fejl" (altså en ikke
> forudset fejl), og pænt spurge om man ville gemme filen alligevel.
> Hvis man sagde ja, så slettede den hele filen!
> Det er blot eet eksempel på at det er svært at komme ud af en ukendt
> tilstand på en fornuftig måde.
> Den kortsigtede løsning var _altid_ at svare nej. Den langsigtede løsning
> var at forbedre stabiliteten.
Forkert langsigtet løsning. Den rette langsigtede løsning ville have
været at en sådan nødsave sikrede sig selv mod at save rent crap, f.eks.
ved at save med et alternativt filnavn som det kendes fra mange
UNIX-editorer og fra Microsoft Word.
>
> [8<8<8<]
>> En anden fejlantagelse i nogle svar er at range-check kun er en
>> debugging-mekanisme som i et "fejlfrit" program kan disables i
>> produktionskoden.
>
> Hvorfor er range-check speciel ?
Det er de ikke, andre checks er lige så gode eksempler.
> Tester du ved indgangen til enhver member-funktion at "this" pointeren er
> gyldig ?
Hvis jeg implementerer klassen i C er svaret normalt ja! I C++ er
svaret nej.
> Hvis ikke: hvorfor ?
C++ vil ofte have derefereret this allerede i det øjeblik kaldet blev
foretaget (gælder især hvis objektet kaldes med punktum i stedet for ->,
eller hvis funktionen er virtuel), så en sådan check vil sjældent fange
noget. Dertil kommer at C++ selv antager at this aldrig er NULL og
derfor kan bortoptimere udtrykket (this == NULL). Endelig kan
nedarvningsforhold få C++ til at lægge små konstanter til NULL før NULL
bliver til this, hvilket gør testen meget sværere.
> Under udvikling (debug build) checker jeg normalt _samtlige_ this-pointere,
> _alle_ pointer operationer inklusiv range check etc. (det er et værktøj som
> gør det).
God ide, er det et kendt værktøj jeg kan tilføje til mine unit-tests?
> Men i release build er det disablet, fordi programmet kører ca. 10 gange
> langsommere.
Det tyder på at testen ikke samarbejder med optimizeren, eller at dit
buildmiljø generelt disabler optimizeren på debug-builds. Især
whole-program-optimization burde kunne eliminere alle de tests som
statisk kan verificeres at være i orden.
>
>
> [8<8<8<]
>> En tredje fejlantagelse er at det ikke er spor slemt at lukke et program
>> ned ved fejl.
>
> Du fusker med citaterne !!!
> Hvor i denne tråd har nogen sagt at det ikke er spor slemt ?
Ingen steder direkte, men mange steder er det blevet skrevet at i denne
eller hin situation bør man aborte/asserte uden nogen angivelse af at
dette er problematisk.
>
>> Det kommer meget an på programmet og må derfor ikke dikteres af generelle
>> klassebiblioteker.
>
> Jeps
> Men generelle biblioteker må gerne stille krav, som kalderen skal overholde
> for at få den ønskede virkning.
Ja, men krav som går ud over selve biblioteksinterfacet (f.eks. at det
er acceptabelt at biblioteket terminerer programmet) kan være ekstremt
problematiske hvis kalderen befinder sig i et miljø uden den egenskab.
>
>> Nogen programmer (f.eks. Webservere) skal bare køre 24x7, og en halvdårlig
>> kørsel er bedre end slet ingen kørsel.
>
> Gælder det altid ?
Nej, men ofte, og kun så længe man kan holde sig indenfor en
applikationsspecifik definition af forskellen på halvdårlig og heldårlig.
> Hvad hvis man udnytter en programmerings fejl i webserveren (eller en af de
> applikation den kører) til at få kontrol over computeren ?
Det ville være en heldårlig kørsel. Min pointe er lige præcis at kode i
en muddle-through process er nødt til at være runtime-paranoid med sine
argumenter og reducere nonsens-værdier (f.eks. out-of-range index) til
ufarlige værdier (f.eks. 0, NULL eller EOF/INVALID_HANDLE_VALUE).
>
> Hvis man kigger på en Webserver som Microsoft IIS, så har den forskellige
> modeller for hvordan man kan eksekvere udvidelser (web applikationer).
> Der er et trade-off mellem performance og pålidelighed.
> Man kan konfigurere IIS således at selve serveren kører i een process og
> hver udvidelse (f.eks. ASP applikation) kører i hver sin process.
> Det betyder at man har operativ-systemet og hardware til at beskytte selve
> serveren og udvidelserne fra hinanden, så en applikation der går amok ikke
> kan slå IIS serveren ned.
>
> Det er netop en løsning, hvor man i tilfælde af uforudsete fejl kan bringe
> programmet (IIS) i en kendt tilstand.
>
> Noget tilsvarende er argumentationen for micro-kernel operativ systemer.
>
>
Enig, det jeg argumenterer for er at bruge den samme filosofi på
programdele med mindre granularitet end processer. En ting er at bringe
hele programdelen i en "kendt tilstand" (læs: tom nultilstand), noget
andet er blot at bringe den konkrete dataværdi i en kendt tilstand men
samtidig bevare de øvrige data. I IIS-programmer bliver tilstanden ofte
lagt over i en SQL Server process hvor de kan overleve et IIS-crash, i
mange andre programmer findes denne luksus ikke.


--
Jakob Bøhm, M.Sc.Eng. * jb@danware.dk * direct tel:+45-45-90-25-33
Danware Data A/S * Bregnerodvej 127 * DK-3460 Birkerod * DENMARK
http://www.netop.com * tel:+45-45-90-25-25 * fax tel:+45-45-90-25-26
Information in this mail is hasty, not binding and may not be right

Mogens Hansen (15-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 15-05-07 21:51

>
>"Jakob Bøhm" <jb@danware.dk> wrote in message
>news:464968fe$0$14015$edfadb0f@dread15.news.tele.dk...
>Mogens Hansen wrote:

[8<8<8<]
>> Det har ikke noget med exceptions a gøre.
>
>Tag følgende funktion (lavet med pointere i stedet for referencer for at
>kunne lave en runtime check):

Hvilket run-time check kan man lave med pointere men ikke reference ?
(Du har stadig muligheden for at sige at det var en finke der røg af panden
)

>
>template<T> bool swap(T *pa, T *pb)
>{
> T x;

Hvorfor ikke initialisere når den erklæres, og erklære den efter checket ?

> if (pa && pb) {

T x = *pa;

> x = *pa;
> *pa = *pb;
> *pb = x;
> return true;
> }
> return false;
>}
>
>Hvis T er en normal type kan man med sikkerhed regne med at funktionen
>enten bytter om på a og b eller gør ingenting. Det er let at resonere med
>hensyn til opretholdelse af invarianter m.m.
>
>Hvis T er en klasse som kan throwe en exception (f.eks. xalloc) i sin
>operator =, så kan man ikke længere antage noget som helst om opretholdelse
>af invarianter,

Det kommer an på hvad man definerer som invariant.

Hvis invarianten er at alle objekter skal kunne nedlægges på lovlig vis, kan
den nemt være opretholdt, hvis operator= lover det. Det er "basic exception
guarantee".

Hvis man definerer det som enten går det helt godt ellers sker der ingen
ændring ("strong exception guarantee") har du ret.

> da man risikerer at blive efterladt med to kopier af den ene værdi, men
> ingen af den anden. For at få en forudsigelig og verificerbar semantik
> bliver man nødt til at tilføje en masse try blokke eller bruge
> dummy-klasser til at simulere __finally-blokke.

Nej - du tager fejl.
Hvis assignment operator ikke giver nogen garantier og man ikke har andre
funktioner, kan man i dette eksempel ikke implementere "Strong exception
guarantee" - enten går det helt godt ellers er der ikke sket noget.
Uanset hvor mange try/catch blokke man laver kan man kun opnå "Basic
exception guarantee".
Typisk er det et tegn på problemer hvis der er en masse try/catch blokke.

Hvis du mener at det kan lade sig gøre at lave løsning med "strong exception
guarantee", alene med en operator= der kan smide exceptions, så vis os
koden.
Typisk skal klassen have en nothrow swap funktion for at det kan lykkes.

> Læremestre udi pure C++-thinking elsker at pille den slags eksempler fra
> hinanden enkeltvis og så påstå de har modbevist problemets eksistens i
> almindelighed.

Hvor har du oplevet det - helt konkret ?
Jeg har hørt problematikkerne omkring exception håndtering beskrevet af
_meget_ kompetente personer (bl.a. Herb Sutter, Andrei Alexandrescu, David
Abrahams og Bjarne Stroustrup) er har ikke oplevet at der er blevet vildledt
eller eller fejet noget ind under gulvtæppet.
Man se et billede jeg har taget fornyligt af Andrei Alexandrescu
http://www.hansen4.dk/fotoalbum/displayimage.php?album=54&pos=10
hvor han netop holder en super forelæsning om exception og fejlhåndtering
generelt.
Der bliver, som det det fremgår af billedet, ikke påstået at det er nemt
eller problemfrit.

På Bjarne Stroustrups hjemmeside
http://www.research.att.com/~bs/3rd_safe0.html
kan man finde Appendix E om exception safety.

Men lad os tage dit eksempel, og sige vi har brug for en swap funktion, og
vi bruger ikke operator overloading og exceptions, men "almindelig"
funktionskald der returner fejlkoder.
Så får vi:

bool swap(T& ta, T& tb)
{
T temp; // unitialized structure
error_type error_code = init(temp, ta); // may fail;
if(SUCCESS != error_code)
// no harm has happened
return error_code;

error_code = assign(ta, tb);
if(SUCCESS != error_code)
// some harm may have happened
return error_code;

error_code = assign(tb, temp);
if(SUCCESS != error_code) {
// ta _has_ been changed
// try to recover ta
if(SUCCESS != assign(ta, temp)) {
return ABSOLUTELY_TOASTED; // !!!
}
// no harm has happened - but function failed
return error_code;
}

return SUCCESS;
}

Man kan forestille sig assign_implementeret som
error_code assign(T& ta, T& tb)
{
static unsigned call_count = 0;
if(call_count)
return failed;

++call_count;
// Do what-ever is needed
// ...
return SUCCESS;
}

Hvilken forskel er der på om operator= kan smide en exception og assign som
returnere en fejlkode ?
Essensen er at *pa _er_ blevet ændret og *pb=x fejler, og så kan man hverken
komme frem eller tilbage (fordi *pa=x formodentlig også vil fejle).

For at programmet skal have muligheden for at køre videre, skal der gælde 2
ting uanset om der bruges exceptions eller fejlkode:
* Fejlen skal rapporteres tilbage til kalderen, som må tage stilling til
hvad der skal gøre
* Programmet skal være i en konsistent (ikke nødvendigvis
vel-specificeret) tilstand så der kan ryddes op.
Det svarer til "Basic exception guarantee".

Lige nøjagtig swap som ikke fejler er en væsentlig funktion i forbindelse
med exception sikker kode.
Det er nødvendigt at have nogle operationer, som garanteret ikke fejler.
Det svarer til "Nothrow guarantee"

[8<8<]
>> Den kortsigtede løsning var _altid_ at svare nej. Den langsigtede løsning
>> var at forbedre stabiliteten.
>Forkert langsigtet løsning. Den rette langsigtede løsning ville have været
>at en sådan nødsave sikrede sig selv mod at save rent crap,

Det gjorde den _også_.
Pointen er at forsøget på at komme ud af en ukendt tilstand var _fuldkommen_
forfejlet, og var værre end at give op.

[8<8<]
>Dertil kommer at C++ selv antager at this aldrig er NULL og derfor kan
>bortoptimere udtrykket (this == NULL). Endelig kan nedarvningsforhold få
>C++ til at lægge små konstanter til NULL før NULL bliver til this, hvilket
>gør testen meget sværere.

Jeg taler sandelig ikke kun om 0 pointere.
Det kan være dangling pointere, forkert castede pointere, sliced object,
uinitialiserede pointere - mulighederne er mange.
Der skal vedligeholdes en tabel med _alle_ objekter af _alle_ typer, og det
skal verificeres at det objekt man bruger faktisk findes.

>> Under udvikling (debug build) checker jeg normalt _samtlige_
>> this-pointere, _alle_ pointer operationer inklusiv range check etc. (det
>> er et værktøj som gør det).
>God ide, er det et kendt værktøj jeg kan tilføje til mine unit-tests?

Det er Borland CodeGuard, som blot er en compiler switch der får compileren
til at generere dynamisk instrumenterings kode.
Tools BoundsChecker og Purify gør noget af det samme.
http://en.wikipedia.org/wiki/IBM_Rational_Purify
http://en.wikipedia.org/wiki/BoundsChecker
http://en.wikipedia.org/wiki/Memory_debugger

>> Men i release build er det disablet, fordi programmet kører ca. 10 gange
>> langsommere.
>Det tyder på at testen ikke samarbejder med optimizeren, eller at dit
>buildmiljø generelt disabler optimizeren på debug-builds.

Ja - naturligvis er optimizeren disablet i debug builds.
Højt optimeret kode er meget vanskeligt at single-steppe i.


[8<8<8<]
>> Hvad hvis man udnytter en programmerings fejl i webserveren (eller en af
>> de applikation den kører) til at få kontrol over computeren ?
>Det ville være en heldårlig kørsel.

Ok
Så problemet er reduceret til at skelne om en ukendt state er halvdårlig og
heldårlig kørsel ?

--
Venlig hilsen

Mogens Hansen



Arne Vajhøj (18-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 18-05-07 01:31

Jakob Bøhm wrote:
> Mogens Hansen wrote:
>> Der er ingen principiel forskel på fejlhåndtering med exceptions eller
>> retur koder.
> Bortset fra læselighed og overskuelighed.

Netop. De fleste betragter exceptions som værende retur værdier
langt overlegne på de områder.

Arne

Arne Vajhøj (18-05-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 18-05-07 01:29

Jakob Bøhm wrote:
> Arne Vajhøj wrote:
>> Throwing exceptions er ikke nødvendigvis error-is-termination.
>>
> Hele exceptions-mekanismen er i sit grunddesign en "dæmpet" udgaver af
> error-is-termination, hvor man kan stoppe termineringen med en finere
> granularitet end en hel process. Næsten alle andre egenskaber ved
> error-is-termination er der stadig: Al data som ligger i
> funktionsstakken mellem throw() og den relevante catch() tabes eller
> rulles tilbage med generiske ufleksible mekanismer. Et stykke lineær
> kode mister egenskaben at linierne udføres allesammen eller slet ikke.

Det ligger jo i sagens natur.

> Al robust kode skal lave paranoide data-commits i tide og utide for
> "hvad nu hvis jeg pludselig bliver slået ihjel". Der er en høj
> real-world risiko for datatab.

Jeg forstår ikke din argumentation.

Det er vel ikke et argument hverken for eller imod exceptions.

> Udgangspunktet for mine eksempler er det alternative princip at
> funktioner som meningsfuldt kan fejle bør returnere en eksplicit
> angivelse af success/fejl, som kalderen så kan/bør teste på. Denne
> angivelse kan være en separat returparameter som det kendes fra f.eks.
> Microsoft COM (alting returnerer HRESULT, semantiske returværdier
> anbringes i referenceargumenter) eller det kan være en veldefineret
> out-of-range værdi for den normale returparameter som det kendes fra
> f.eks. traditionelle C API-er som fopen() og fgetch(). Den sidstnævnte
> løsning er især praktisk hvis man samtidig laver en designregel om at
> sådanne fejlværdier propageres som fejlværdier overalt, ligesom det
> kendes fra IEEE NaNs etc. Hvis man for eksempel propagere -1 som indeks
> til et nyt opslag i en funktion med rangecheck, så får man igen en
> fejlreturværdi o.s.v. At en funktion returnerer den rette
> fejlindikering ved ugyldigt input er naturligvis en del af den kontrakt
> som skal testes med unit-tests.

Der er mange (inkl. mig) som mener at exceptions er en betydeligt
pænere måde at gøre det på end et hav af if's på retur værdier.

> En tredje fejlantagelse er at det ikke er spor slemt at lukke et program
> ned ved fejl. Det kommer meget an på programmet og må derfor ikke
> dikteres af generelle klassebiblioteker. Nogen programmer (f.eks.
> Webservere) skal bare køre 24x7, og en halvdårlig kørsel er bedre end
> slet ingen kørsel.

Det er jeg enig i.

Arne


Mogens Hansen (10-05-2007)
Kommentar
Fra : Mogens Hansen


Dato : 10-05-07 05:59


"Janus" <jan@no.mail.no> wrote in message
news:4641ee52$0$21926$157c6196@dreader1.cybercity.dk...

[8<8<8<]
> Jo, templateudgaven smider ens array sammen med resten af klassens data,
> hvor den anden udgave putter den et andet sted på heap, men... hvad skulle
> ellers være fordelen ved det? Læser lige nu "c++ templates: the complete
> guide",

Det er en god bog - den bedste om templates.

> hvor eksemplet bruges, men forfateren kommer ikke rigtig ind på hvorfor
> dælen jeg skulle ønske at gøre det sådan.

Der er den væsentlige design forskel at den enes størrelse er statisk på
run-time hvorimod den anden er dynamisk på run-time.

I den virkelige verden findes de 2 klasser:
std::vector<T> - run-time dynamisk størrelse
boost::array<T,n> - compile-time dynamisk, run-time statisk størrelse
(http://www.boost.org/doc/html/array.html)

Generelt kan man ofte få bedre performance ved at bruge compile-time
dynamiske, run-time statiske konstruktioner, fordi beregninger kan laves på
compile-time i stede for på run-time. Dertil kommer at compileren har flere
muligheder for at lave optimeringer.
Men de er naturligvis kun interessante, når problemet er af en natur der
svarer dertil.

I det konkrete tilfælde sparer man desuden et niveau af indirektion, når man
skal tilgå et element.

Personligt kan jeg ikke huske at have anvendt boost::array<T,n> - normalt
bruger jeg std::vector<T> og praktisk taget aldrig de indbyggede array til
andet end konstante tabeller.

--
Venlig hilsen

Mogens Hansen



Søg
Reklame
Statistik
Spørgsmål : 177554
Tips : 31968
Nyheder : 719565
Indlæg : 6408857
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste