It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.
Echt een juweeltje.
Naja, na de opmerking van super-muffin over de hoofdletters in de eerste query begin ik te vermoeden dat een tweede devver daar ooit de zinloze 'order by'-clause heeft toegevoegd.
Hongaarse notatie? Ik zie geen hongaarse notatie, alleen maar vage prefixessuper-muffin schreef op woensdag 18 juni 2008 @ 13:12:
En dan nog die smerige Hongaarse notatie
Historisch gegroeide code is het. (hoop ik, want anders mag die software knakker z'n spullen gaan pakken).mosymuis schreef op woensdag 18 juni 2008 @ 10:40:
Wie mij de logica kan uitleggen krijgt een bloemetje
Ooit stond de data die nodig is in andere tabellen. En in plaats van een JOIN vroeg hij die op met een query op een andere tabel in de while lus.
Maar dan nog is het niet erg logisch.
[ Voor 4% gewijzigd door remco_k op 18-06-2008 14:21 ]
Alles kan stuk.
(ssh, dat heb ik ook wel eens gedaanmosymuis schreef op woensdag 18 juni 2008 @ 10:40:
PHP:
1 2 3 4 5 6 7 8 9 10 $sBedrijfSQL = "select * from tblBedrijf ORDER BY Naam"; $sBedrijfQuery = mysql_query($sBedrijfSQL); while($aBedrijven = mysql_fetch_array($sBedrijfQuery)) { $bedrijfindex = $aBedrijven['ID']; $sBedrijfSQLas = "select * from tblBedrijf where ID = '$bedrijfindex'"; $sBedrijfQueryas = mysql_query($sBedrijfSQLas); $oBedrijf = mysql_fetch_assoc($sBedrijfQueryas); $aBedrijf[$bedrijfindex] = $oBedrijf; }
Wie mij de logica kan uitleggen krijgt een bloemetje
Haha nou vind hem niet zo erg heb in mijn verleden wel ergere dingen op mijn kerfstok. Je begint toch met copy plakken en vage $tmpDit en $DoeHet variabelen om het te leren.YopY schreef op donderdag 19 juni 2008 @ 11:47:
[...]
(ssh, dat heb ik ook wel eens gedaan. Comments voor een bepaalde nieuwpost uit een database halen. Ik schaam mij diep ondertussen)
Hij deed het wel
[ Voor 10% gewijzigd door vorlox op 26-06-2008 18:26 ]
Euh en wat is daar dan erg aan? Als je een join doet krijg je je nieuwsbericht (aantal comments) keer terug en daarnaast zul je dan weer met ifs moeten gaan klooien om het alsnog goed te krijgen.YopY schreef op donderdag 19 juni 2008 @ 11:47:
[...]
(ssh, dat heb ik ook wel eens gedaan. Comments voor een bepaalde nieuwpost uit een database halen. Ik schaam mij diep ondertussen)
Daarnaast is het sowieso onzinnig, want je wilt nooit de nieuwsberichten laten zien met daarbij meteen de comments. Daar heb je doorgaans een aparte pagina voor waar je bovenaan het nieuwsbericht ziet en daaronder de comments die bij dat ene bericht horen.
Als je voor dat laatste een join gaat gebruiken ben je imho wel heel erg micro-optimalistisch (is dat een woord?) bezig. Daarnaast komt het de leesbaarheid van de code die het nieuwsbericht en de comments in de goede volgorde laat zien ook niet ten goede, want dan moet je met een if in de while van de comments gaan zitten klooien, of je moet de eerste comment ophalen om het nieuwsbericht te laten zien en vervolgens weer terug "seeken" naar het allereerste result om vervolgens toch alle comments te kunnen laten zien.
PV: Growatt MOD5000TL3-XH + 5720wp, WPB: Atlantic Explorer v4 270LC, L/L: MHI SCM 125ZM-S + SRK 50ZS-W + 2x SRK 25ZS-W + SRK 20ZS-W Modbus kWh meter nodig?
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
$aBedrijf was al bezet, dus dan moet je creatief gaan doen.Cartman! schreef op donderdag 26 juni 2008 @ 17:20:
Ook een leuk detail: $oBedrijf is geen object maar een array
Trouwens nog een leuke om mijn post aan te vullen:
1
2
3
4
| if ( in_array($var, array('blaat')) ) { print 'w00t'; } |
[ Voor 22% gewijzigd door Michali op 27-06-2008 00:26 ]
Opzich is daar niet veel mis mee, true, in deze vorm is het wat raar, maar wellicht stonden er eerst meer items in die array. Zodat je niet een shitload aan expressies krijgt waardoor het onoverzichtelijk wordt.Michali schreef op vrijdag 27 juni 2008 @ 00:24:
Trouwens nog een leuke om mijn post aan te vullen:
PHP:
1 2 3 4 if ( in_array($var, array('blaat')) ) { print 'w00t'; }
- ik weet niet of iemand het herkend -
Als ik mooie goedwerkende code heb, dan begin ik achteraf vaak nog een paar details toe te voegen/tweaken, en dan krijg je vlug dat je propere code er helemaal niet meer proper uit ziet...
Gewoon een vraagje of een pro-programmeur dat herkent?
Ik ga niet heel m'n programma beginnen herschrijven om een detail op te vangen. Ik voeg gewoon een nieuwe variabele ergens in, die de "fout" opvangt.
*True, als je met objecten werkt kun je vaak heel flexible wel nog proffesioneel eraan sleutelen, maar je kunt niet alles in objecten zetten. (allessinds niet zinvol) Wel een reden waarom ik "in love" ben met objecten. (Geeks zijn rare mensen)
Ik stel voor dat je eens met Microsoft of EA Games moet praten. Hoewel ze het niet zullen toegeven hebben ze precies hetzelfdeg4wx3 schreef op vrijdag 27 juni 2008 @ 12:21:
Ik heb nooit ICT gestudeert, maar ik doe wel m'n best om altijd professionele code te schrijven.
- ik weet niet of iemand het herkend -
Als ik mooie goedwerkende code heb, dan begin ik achteraf vaak nog een paar details toe te voegen/tweaken, en dan krijg je vlug dat je propere code er helemaal niet meer proper uit ziet...
(...)
[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]
Verwijderd
Leuk is dat he, een taal waarbij je uit de naam van de variable het type op moet makenCartman! schreef op donderdag 26 juni 2008 @ 17:20:
Ook een leuk detail: $oBedrijf is geen object maar een array
? Zonder ide haal je in C# ook niet uit de naam het variabeletypeVerwijderd schreef op vrijdag 27 juni 2008 @ 12:38:
[...]
Leuk is dat he, een taal waarbij je uit de naam van de variable het type op moet maken
Ik denk niet dat het er ooit nog gaat komen, met bepaalde objecten zoals Directory e.d. heeft PHP wel dit object geörienteerde maar daar blijft het ook bij.
[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]

{signature}
Waarom is dat handiger? Ik zie geen verschil.Sebazzz schreef op vrijdag 27 juni 2008 @ 12:43:
Het is veel handig om $array->pop(); te doen dan array_pop($array);
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Tegenwoordig prefereert men al snel pop_array($array), omdat $array dan alles kan zijn wat aan de benodigde concepten voldoet. Anders moet het perse een object zijn met een member functie pop_array. Object oriented programming maakt plaats voor concept based programming.
[ Voor 65% gewijzigd door Zoijar op 27-06-2008 13:19 ]
Verwijderd
Bij $array->pop () kun je de method overloaden als je een derived class gebruikt. Bij het aanroepen van een functie heb je dat voordeel niet. Het is niet mogelijk de array_* functies te overloaden.
Functie overloads. (ok, in PHP misschien niet)Verwijderd schreef op vrijdag 27 juni 2008 @ 13:19:
Bij $array->pop () kun je de method overloaden als je een derived class gebruikt. Bij het aanroepen van een functie heb je dat voordeel niet. Het is niet mogelijk de array_* functies te overloaden.
[ Voor 4% gewijzigd door Zoijar op 27-06-2008 13:20 ]
Je ziet dat bij de mysqli extension er zowel OO als functie-gericht geprogrammeerd kan worden.Sebazzz schreef op vrijdag 27 juni 2008 @ 12:43:
[...]
? Zonder ide haal je in C# ook niet uit de naam het variabeletypemaar je punt is duidelijk. Het is wel jammer natuurlijk, en ook een van de grootste nadelen van PHP. Ik vindt het ook jammer dat niet zoals in C# alles een object is. Het is veel handig om $array->pop(); te doen dan array_pop($array);.
Ik denk niet dat het er ooit nog gaat komen, met bepaalde objecten zoals Directory e.d. heeft PHP wel dit object geörienteerde maar daar blijft het ook bij.
Ik dacht dat in php6 het OO principe beter zou worden uitgewerkt, dus hopelijk krijg je dan ook die mogelijkheden (waarbij array_pop alleen het Array object accepteert bijv). Heb je backwards compatibility en makkelijkere methods tot je beschikking.
Maar niet als je de derived class niet zelf gemaakt hebt, wat bij functies weer wel kan. In PHP kun je dan wel weer geen functies overloaden, maar wel zelf een andere functie maken die iets doet aan de hand van de parameter die wordt meegegeven. Dus geen array_pop(), maar wel een cheatah_pop().Verwijderd schreef op vrijdag 27 juni 2008 @ 13:19:
[...]
Bij $array->pop () kun je de method overloaden als je een derived class gebruikt.
Ik ben er dan ook voorstander van om zo min mogelijk methods toe te voegen aan classes die geen private of protected members van de class gebruiken, op classes die je toch al vrijwel niet ging deriven (zoals arrays of strings).
En met dingen als extension methods zoals in .Net 3(.5?) maakt het geen zak meer uit of je dan pop(array) of array.pop() schrijft - de usage patterns zijn volledig equivalent.
Gelukkig gaat C++0x ook de concepts kant op
[ Voor 31% gewijzigd door .oisyn op 27-06-2008 13:38 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Verwijderd
nicemosymuis schreef op woensdag 18 juni 2008 @ 10:40:
PHP:
1 2 3 4 5 6 7 8 9 10 $sBedrijfSQL = "select * from tblBedrijf ORDER BY Naam"; $sBedrijfQuery = mysql_query($sBedrijfSQL); while($aBedrijven = mysql_fetch_array($sBedrijfQuery)) { $bedrijfindex = $aBedrijven['ID']; $sBedrijfSQLas = "select * from tblBedrijf where ID = '$bedrijfindex'"; $sBedrijfQueryas = mysql_query($sBedrijfSQLas); $oBedrijf = mysql_fetch_assoc($sBedrijfQueryas); $aBedrijf[$bedrijfindex] = $oBedrijf; }
Wie mij de logica kan uitleggen krijgt een bloemetje
[ Voor 63% gewijzigd door Verwijderd op 27-06-2008 15:18 ]
True, en zonder compiler kun je je computer de code niet eens laten uitvoeren, en zonder computer wordt het uitvoeren van de code überhaupt lastigSebazzz schreef op vrijdag 27 juni 2008 @ 12:43:
[...]
? Zonder ide haal je in C# ook niet uit de naam het variabeletype
Feit is dat verreweg de meeste C# programmeurs gewoon een IDE gebruiken. Gedit of vi gebruiken is niet stoer, maar is gewoon dom
It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.
Toch ken ik nog steeds iemand die blijft volhouden dat hij het snelst in Java kan programmeren met vim, icm met make-files. Ik heb hem maar voor gek verklaard, want ik kan alleen al met auto-completion zoveel sneller code schrijven... Plus dat je niet continue een browser open moet hebben met alle javadocs erin.flowerp schreef op vrijdag 27 juni 2008 @ 21:08:
[...]
True, en zonder compiler kun je je computer de code niet eens laten uitvoeren, en zonder computer wordt het uitvoeren van de code überhaupt lastig
Feit is dat verreweg de meeste C# programmeurs gewoon een IDE gebruiken. Gedit of vi gebruiken is niet stoer, maar is gewoon dom
Ik ben iig blij met Eclipse, waarmee je makkelijk kunt zien wat het type van een variabele is en ook of het een locale of member variabele is
Maak jij grappen over yy3 shift-P ZZ?flowerp schreef op vrijdag 27 juni 2008 @ 21:08:
Feit is dat verreweg de meeste C# programmeurs gewoon een IDE gebruiken. Gedit of vi gebruiken is niet stoer, maar is gewoon dom
Hehe
vim editor emulator for Visual StudioZoijar schreef op zaterdag 28 juni 2008 @ 00:48:
[...]
Heheok... Ik gebruik eigenlijk voornamelijk visual studio 2008 IDE, en Kate, en soms vi om bv een waarde te veranderen oid.
Vim kan trouwens wel erg handig zijn voor macro's en dergelijke. Ik heb het zelfs hier gewoon onder windows geïnstalleerd

Ik werk niet anders dan met (g)vim, ook onder windowsMarcj schreef op zaterdag 28 juni 2008 @ 00:52:
Vim kan trouwens wel erg handig zijn voor macro's en dergelijke. Ik heb het zelfs hier gewoon onder windows geïnstalleerd
Met refactoring kun je je bestaande code zo voorbereiden dat je de wijziging op een nette manier kunt doen. Verdiep je er eens wat meer in. Wat je noemt heet overigens Software rot, en moet je, zeker bij grote applicaties door continu doorontwikkeld worden, zeker serieus nemen.g4wx3 schreef op vrijdag 27 juni 2008 @ 12:21:
Ik heb nooit ICT gestudeert, maar ik doe wel m'n best om altijd professionele code te schrijven.
- ik weet niet of iemand het herkend -
Als ik mooie goedwerkende code heb, dan begin ik achteraf vaak nog een paar details toe te voegen/tweaken, en dan krijg je vlug dat je propere code er helemaal niet meer proper uit ziet...
Gewoon een vraagje of een pro-programmeur dat herkent?
Ik ga niet heel m'n programma beginnen herschrijven om een detail op te vangen. Ik voeg gewoon een nieuwe variabele ergens in, die de "fout" opvangt.
*True, als je met objecten werkt kun je vaak heel flexible wel nog proffesioneel eraan sleutelen, maar je kunt niet alles in objecten zetten. (allessinds niet zinvol) Wel een reden waarom ik "in love" ben met objecten. (Geeks zijn rare mensen)
1
2
3
4
5
6
7
| try { //code } catch (Exception e) { } |
Dat heb ik dus aangepast naar iets dat foutmeldingen naar een logbestand schrijft. Vervolgens krijg ik een log van 40MB.. hmm, vreemd..
Blijkt er dus een fout in de code te zitten die bij ieder record dat wordt ingelezen optreedt en netjes wordt opgevangen door het lege catch blok, waardoor een bepaalde functionaliteit gewoon nooit heeft gewerkt


Overigens ook raar dat niemand dat ooit heeft opgemerkt.
Kater? Eerst water, de rest komt later
We are shaping the future
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| if (isset($_REQUEST["login_button"])) { $query = "SELECT * FROM gebruiker"; $result = @mysql_query($query) or die ("Fout bij opzoeken van de gebruiker: ".mysql_error()); while($detail = mysql_fetch_array($result)) { $login_id = $detail["ID"]; $gebruikersnaam = $detail["GebruikersNaam"]; $paswoord = $detail["Paswoord"]; $BezoekDatum = $detail["BezoekDatum"]; $BezoekUur = $detail["BezoekUur"]; $Bezoekaantal = $detail["Bezoekaantal"]; if($_REQUEST["login_naam"] == $gebruikersnaam && md5($_REQUEST["paswoord"]) == $paswoord) { $foutelogin = ""; $time = date("d/m/Y - H:i:s"); $date = date("Y-m-d"); $time = date("H:i:s"); $_SESSION["login"] = "1"; $_SESSION["GebruikersNaam"] = $gebruikersnaam; $_SESSION["LoginTime"] = $time; $_SESSION["LastLoginDate"] = $BezoekDatum; $_SESSION["LastLoginTime"] = $BezoekUur; // Bij eerste maal inloggen, doorsturen naar profielpagina. \\ if ($_SESSION["LastLoginDate"] == "0000-00-00" || $_SESSION["LastLoginDate"] == ""){ $GLOBALS['firstlogin'] = "1"; } $_SESSION["Gebruiker_ID"] = $login_id; $aantal = $Bezoekaantal+1; $query = "UPDATE gebruiker SET BezoekDatum = '".$date."', BezoekUur='".$time."', Bezoekaantal='".$aantal."' WHERE ID = '".$login_id."'"; @mysql_query($query) or die("Fout bij aanpassen van de laatste inlogtijd: ".mysql_error()); // Voeg actie toe in de log. \\ $log_id = $login_id; $log_action = "Ingelogd."; $log_datum = date("Y-m-d"); $log_uur = date("H:i:s"); $query_log = "INSERT INTO log (log_ID , log_gebruiker_ID, log_action, log_datum, log_uur) VALUES ('', '$log_id', '$log_action', '$log_datum', '$log_uur')"; @mysql_query($query_log) or die("Fout bij toevoegen van de log gegevens: ".mysql_error()); break; } else{ $foutelogin = "Verkeerde Naam of Paswoord."; } } } |
Ach ja... ik kom zo nu en dan ook eens code tegen waarvan ik denk "huh? maar dat werkt toch helemaal niet?", wat na verificatie idd ook niet blijkt te werken. En dat is dan code die er sinds Tomb Raider: Legend al in zat. Oh wellHaan schreef op zaterdag 28 juni 2008 @ 13:43:
Blijkt er dus een fout in de code te zitten die bij ieder record dat wordt ingelezen optreedt en netjes wordt opgevangen door het lege catch blok, waardoor een bepaalde functionaliteit gewoon nooit heeft gewerktal bijna een jaar lang
Overigens ook raar dat niemand dat ooit heeft opgemerkt.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Wat is een paswoord?moozzuzz schreef op vrijdag 04 juli 2008 @ 16:23:
Opnieuw een beetje PHP als eigenaarigheidje. Volgens mij toch...
[...]
Ik moest hem wel even twee keer doorlezen voordat ik doorhad wat er nu echt gebeurt, maar...
Ik heb hem ook twee keer moeten doorlezen maar ben er nog niet helemaal zeker van. Zit het hem erin dat alle gebruikers worden terug gegeven terwijl je weet van welke gebruik rehet af komt (onnodige loop) of??Marcj schreef op vrijdag 04 juli 2008 @ 16:33:
[...]
Wat is een paswoord?
Ik moest hem wel even twee keer doorlezen voordat ik doorhad wat er nu echt gebeurt, maar...
- Een @ onderdrukt toch foutmeldingen, inclusief de or die statements?
- Waarom worden er geen datetime velden gebruikt?
En een WTF niet gerelateerd aan PHP:
Je loopt eerst door een hele dataset heen om een gebruiker te updaten? Is het een dermate oude DB dat er geen WHERE gebruikt mag worden?
zo niet, zeg het dan even
Heart..pumps blood.Has nothing to do with emotion! Bored

[ Voor 6% gewijzigd door .oisyn op 04-07-2008 16:49 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Nee, die() produceert geen foutmelding.TeeDee schreef op vrijdag 04 juli 2008 @ 16:40:
Het eerste wat me te binnen schiet, zonder PHP kennis:
- Een @ onderdrukt toch foutmeldingen, inclusief de or die statements?

Is inderdaad de login-procedure van een hobby-site waar ik in principe de HTML zou gaan opkuisen, maar ik ga het niet kunnen laten hier en daar mijn *suggesties* te geven...
@Webgnome:
Ik vond het vooral verrassend dat men zoveel onnodige resources verspilt, waar dit lapje code een voorbeeld is... Er zijn maar een 2000 gebruikers maar toch...
@teeDee:
Ik vermoed eigenlijk dat iemand niet wist dat er username like 'xxx' bestond. Ook andere delen vd site hebben nl last van de while.
Ik zal het vanavond ontdekken: dan komen we samen met het 'webteam' om mij de structuur vd website te leren kennen
@ .oisin:
Inderdaad niet allemaal zo van die "gevaarlijke" fouten, maar als je weet dat de core van de website geschreven is door iemand die ook professioneel proggert... (vul zelf aan ;^)
[ Voor 12% gewijzigd door moozzuzz op 04-07-2008 17:02 ]
Verwijderd
Hoezo 'like'... gewoon WHERE name = 'naam' AND pw = 'pw'...niet moeilijk doen als het ook makkelijk kanmoozzuzz schreef op vrijdag 04 juli 2008 @ 16:59:
@teeDee:
Ik vermoed eigenlijk dat iemand niet wist dat er username like 'xxx' bestond. Ook andere delen vd site hebben nl last van de while.
En LIKE gebruiken zou een nog grotere WTF zijn dan het overlopen van 2000 gebruikersVerwijderd schreef op vrijdag 04 juli 2008 @ 17:02:
[...]
Hoezo 'like'... gewoon WHERE name = 'naam' AND pw = 'pw'...niet moeilijk doen als het ook makkelijk kan.
Heart..pumps blood.Has nothing to do with emotion! Bored
En in productie code doe je geen or die(mysql_error())...

{signature}
Verwijderd
Dit is (gelukkig?) dan ook geen productie codeVoutloos schreef op vrijdag 04 juli 2008 @ 17:11:
En in productie code doe je geen or die(mysql_error())...
In de voorbeeldcode. Helaas zijn er andere bestanden in het project die veel kleiner zouden zijn met een LIKE.TeeDee schreef op vrijdag 04 juli 2008 @ 17:05:
En LIKE gebruiken zou een nog grotere WTF zijn dan het overlopen van 2000 gebruikers
Hmmz... het is óok geen test/debug-codeVerwijderd schreef op vrijdag 04 juli 2008 @ 17:19:
Dit is (gelukkig?) dan ook geen productie code.
Begrijp ik je goed en promoot jij het gebruik van LIKE in een user-check-systeem-ding?moozzuzz schreef op vrijdag 04 juli 2008 @ 18:44:
[...]
In de voorbeeldcode. Helaas zijn er andere bestanden in het project die veel kleiner zouden zijn met een LIKE.
[...]
Hmmz... het is óok geen test/debug-code. Dit beest staat toch echt als finale versie online hoor.
Heart..pumps blood.Has nothing to do with emotion! Bored
Dat wordt leuk als je 5000 records in je database hebtTeeDee schreef op vrijdag 04 juli 2008 @ 18:54:
[...]
Begrijp ik je goed en promoot jij het gebruik van LIKE in een user-check-systeem-ding?
[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]
Verwijderd
Je gaf zelf toch aan dat het om een hobby site ging?moozzuzz schreef op vrijdag 04 juli 2008 @ 18:44:
[...]
Hmmz... het is óok geen test/debug-code. Dit beest staat toch echt als finale versie online hoor.
Bij 'productie code' denk ik aan bedrijven die je een opdracht geven, waarvoor je betaald wordt etc.
Uiteraard kun je ook gewoon je invoerveld goed checken vooralleer je een request doet, zoals de meeste. devvers het doen
Wat valt er te checken aan een username? Als jij "' OR 1" wilt heten dan moet dat gewoon kunnen imhog4wx3 schreef op vrijdag 04 juli 2008 @ 21:49:
Uiteraard kun je ook gewoon je invoerveld goed checken vooralleer je een request doet, zoals de meeste. devvers het doen
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
.oisyn schreef op vrijdag 04 juli 2008 @ 16:27:
[...]
Ach ja... ik kom zo nu en dan ook eens code tegen waarvan ik denk "huh? maar dat werkt toch helemaal niet?", wat na verificatie idd ook niet blijkt te werken. En dat is dan code die er sinds Tomb Raider: Legend al in zat. Oh well
Heb van de week TRL opgepikt voor 6 euro, om mn TR collectie aan te vullen.
Die try catch constructie heb ik zelf vandaag nog gebruikt. We gebruiken een webservice om gegevens op de homepage van onze klant te plaatsen. Had de oorspronkelijke coder daar geen exception handling omheen gebouwd. Blijkt vandaag die webservice eruit te liggen, en gaf die homepage een exception. ><
De "paniek" was ietsie groter ook nog, omdat de knuppel die het project als laatste onderhanden heeft gehad het voor elkaar heeft gekregen om 2 LLBLGen generated projecten te doen verdwijnen bij het inchecken. Dus, na wat geklooi, (de binaries van die twee projecten van de webserver geplukt en in het project geinclude), heb ik snel even afgevangen met een lege try catch.
Niet echt mooi natuurlijk, maar een paar missende veldjes op de homepage is beter dan geen homepage. Gelukkig was ik toch al bezig met een complete rewrite van die website.
Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info
Waarom dan een leeg catch-block? Zo moeilijk is het niet om de exceptie dan naar een log-bestand weg te schrijven. En je zou toch echt wel een nette foutmelding moeten geven (desnoods een code 500, internal server error).Grijze Vos schreef op zaterdag 05 juli 2008 @ 01:55:
[...]
offtopic:
Heb van de week TRL opgepikt voor 6 euro, om mn TR collectie aan te vullen.Leuke game, ben er wel op 10 uurtjes spelen al 70% doorheen.
Die try catch constructie heb ik zelf vandaag nog gebruikt. We gebruiken een webservice om gegevens op de homepage van onze klant te plaatsen. Had de oorspronkelijke coder daar geen exception handling omheen gebouwd. Blijkt vandaag die webservice eruit te liggen, en gaf die homepage een exception. ><
De "paniek" was ietsie groter ook nog, omdat de knuppel die het project als laatste onderhanden heeft gehad het voor elkaar heeft gekregen om 2 LLBLGen generated projecten te doen verdwijnen bij het inchecken. Dus, na wat geklooi, (de binaries van die twee projecten van de webserver geplukt en in het project geinclude), heb ik snel even afgevangen met een lege try catch.
Niet echt mooi natuurlijk, maar een paar missende veldjes op de homepage is beter dan geen homepage. Gelukkig was ik toch al bezig met een complete rewrite van die website.
Een keer een query overgekopieerd, maar vergeten aan te passen, maar het werkte wel.oisyn schreef op vrijdag 04 juli 2008 @ 16:27:
[...]
Ach ja... ik kom zo nu en dan ook eens code tegen waarvan ik denk "huh? maar dat werkt toch helemaal niet?", wat na verificatie idd ook niet blijkt te werken. En dat is dan code die er sinds Tomb Raider: Legend al in zat. Oh well
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| $db->query("SELECT AVG(rating) FROM video LEFT JOIN rating ON rating.rateid = video.id AND rating.typeid = 3 WHERE video.userid = '".$user->userid."' AND video.id = '".$id."' GROUP BY rating.rateid"); $max = $db->num_rows(); if($max > $config['max_allowed']) { |
Ik zie productiecode als software die echt gebruikt wordt door gebruikers, en daar tegenover staat dan de ontwikkelversie waaraan je sleutelt en die nog niet af is.Verwijderd schreef op vrijdag 04 juli 2008 @ 19:16:
[...]
Je gaf zelf toch aan dat het om een hobby site ging?
Bij 'productie code' denk ik aan bedrijven die je een opdracht geven, waarvoor je betaald wordt etc.
Er zijn een aantal fases waarin een project in kan verkeren waarvan de meeste gebruikte development, beta en productie. Het feit dat een tool door anderen wordt gebruikt betekend niet automatisch dat het geen hobby project meer is. Productie behoort stabiel en geteste code te zijn.
If it isn't broken, fix it until it is..
Soms wil je gewoon iets proberen, en als het fout gaat dan is het niet zo erg: dan doe je het gewoon niet. Dat soort dingen wil je niet onnodig een error log mee vullen. Het is niet heel erg netjes, maar ik doe het ook soms. Of bijvoorbeeld dit soort dingen:Marcj schreef op zaterdag 05 juli 2008 @ 08:58:
Waarom dan een leeg catch-block? Zo moeilijk is het niet om de exceptie dan naar een log-bestand weg te schrijven. En je zou toch echt wel een nette foutmelding moeten geven (desnoods een code 500, internal server error).
1
2
3
4
5
6
7
8
| try { while (1) { ifs >> ts1 >> ts2 >> dummy >> dummy >> nr >> dummy >> x1 >> y1 >> dummy >> dummy >> x2 >> y2 >> dummy; if (nr == 2) { blobs1.push_back(std::make_pair(x1, y1)); blobs2.push_back(std::make_pair(x2, y2)); } } } catch (...) {} |
Ik wil hier gewoon regels inlezen tot het mis gaat, meestal bij een eof(). Eigenlijk moet ik in die catch iets schrijven als: if (!ifs.eof()) throw; maar dat schiet er vaak bij in...
Omdat ik toch niks met dat log zou doen.Marcj schreef op zaterdag 05 juli 2008 @ 08:58:
[...]
Waarom dan een leeg catch-block? Zo moeilijk is het niet om de exceptie dan naar een log-bestand weg te schrijven. En je zou toch echt wel een nette foutmelding moeten geven (desnoods een code 500, internal server error).
Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info
Het haalt de kracht achter try...catch een beetje weg. Het maakt code foutgevoeliger, want voor de gebruiker/tester gaat er niets mis terwijl er eigenlijk continue code faalt en daar geen melding van geeft door het lege catch blok.
Daarom: altijd even een logje, debug- of foutmelding weergeven is mijn mening.
Zelf heb ik in Eclipse ingesteld dat hij moet waarschuwen als er lege bodies zijn. Dan ben je wel genoodzaakt er iets mee te doen, al is het maar om de warning kwijt te raken
More than meets the eye
There is no I in TEAM... but there is ME
system specs
Verwijderd
Inderdaad, ReSharper (plugin voor Visual Studio, C#) geeft ook meldingen van lege Catch blokken...echt netjes staat het niet nee. Komt gewoon op het onderdrukken van exceptions neerIceManX schreef op maandag 07 juli 2008 @ 13:04:
En zelfs al wil je geen logging, zet er dan een stukje commentaar in WAAROM je de exceptie negeert.
Zelf heb ik in Eclipse ingesteld dat hij moet waarschuwen als er lege bodies zijn. Dan ben je wel genoodzaakt er iets mee te doen, al is het maar om de warning kwijt te raken
Verwijderd
En onderdrukken van excepties komt wel vaker voor, en soms ook met goede redenen dat het niet eens een debug message waard is. Vaak doe ik dan iets als:Verwijderd schreef op maandag 07 juli 2008 @ 13:45:
Inderdaad, ReSharper (plugin voor Visual Studio, C#) geeft ook meldingen van lege Catch blokken...echt netjes staat het niet nee. Komt gewoon op het onderdrukken van exceptions neer.
1
2
3
4
5
6
7
8
9
| InputStream in = null; try { //Stream creation and reading } catch(IOException e){ LOG.warn("log me", e); } finally { try{if(in != null) in.close();} catch(IOException ignorable) {} } |
Prima leesbaar en je hoeft er toch niet meer commentaar kwijt.
Verwijderd
Deze javanist ook hoorZoijar schreef op maandag 07 juli 2008 @ 16:04:
Resource-release-methoden die een exception kunnen gooien: dat geeft een C++-er koude rillingen.
Weleens een ongeopende std::fstream proberen te sluiten met close() terwijl exceptions op de stream aanstonden?Zoijar schreef op maandag 07 juli 2008 @ 16:04:
Resource-release-methoden die een exception kunnen gooien: dat geeft een C++-er koude rillingen.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Neemt niet weg dat ik onlangs eens raar stond te kijken toen ik eens een manual close() deed in een catch handler om de file opnieuw te openen
[ Voor 5% gewijzigd door .oisyn op 07-07-2008 16:20 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ik close die dingen nooit; ik ga ervan uit dat de dtor dat veilig doet....oisyn schreef op maandag 07 juli 2008 @ 16:09:
Weleens een ongeopende std::fstream proberen te sluiten met close() terwijl exceptions op de stream aanstonden?
Maar dit is idd enge code:
1
2
3
4
5
6
7
8
9
10
11
| class X { public: std::fstream fs; X() { fs.exceptions(std::ios::failbit | std::ios::badbit | std::ios::eofbit); } ~X() { fs.close(); } }; |
Wist ik eerlijk gezegd niet. Verbazingwekkend.
Hmm nu vraag ik me ineens af, stel je specificeert expliciet een lege throw spec, geldt die dan ook voor de members van T, die feitelijk pas worden gedestruct nadat de code in de dtor van T is uitgevoerd?
.edit: nvm, deze gedachtenkronkel slaat sowieso nergens op. Een lege throw spec eet geen exceptions, hij zorgt er alleen voor dat unexpected() wordt aangeroepen zodra er een exception optreedt.
[ Voor 76% gewijzigd door .oisyn op 07-07-2008 16:31 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ja, unexpected() of terminate() is ook weinig feitelijk verschil. Dus eigenlijk bestaat die restrictie al, min of meer..oisyn schreef op maandag 07 juli 2008 @ 16:28:
.edit: nvm, deze gedachtenkronkel slaat sowieso nergens op. Een lege throw spec eet geen exceptions, hij zorgt er alleen voor dat unexpected() wordt aangeroepen zodra er een exception optreedt.
Vroeger deed ik in Javascript het volgende:
1
| <div onmouseover="this.style.cursor='hand';" onmouseout="this.style.cursor='default';"></div> |
If then else matters! - I5 12600KF, Asus Tuf GT501, Asus Tuf OC 3080, Asus Tuf Gaming H670 Pro, 48GB, Corsair RM850X PSU, SN850 1TB, Arctic Liquid Freezer 280, ASUS RT-AX1800U router
Verwijderd
Hoe kom je daar nou bij? Je kunt op zich probleemloos een exception throwen in een destructor, het zou m.i. zelfs tragisch zijn indien dat niet mogelijk zou zijn.Zoijar schreef op maandag 07 juli 2008 @ 16:13:
... in C++ is het meteen program terminate zodra een destructor een exception throwed...
Wat fout afloopt is het throwen van een exception tijdens de afhandeling van een andere exception. Voorbeeld:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| #include <iostream> class T { public: ~T (void) { throw 0; } }; int main (void) { try { T t[1]; } catch (...) { std::cout << "Exception caught" << std::endl; } std::cout << "End of program." << std::endl; return 0; } |
In dit voorbeeld wordt de exception keurig afgevangen. Maar verander op regel 14: '[1]' in '[2]', en je krijgt - zoals verwacht - een abnormal program termination.
Een voorbeeld waarmee het probleem van potentieel throwen tijdens de afhandeling van een user-exception geïllustreerd kan worden, is het volgende (wrapper-class rond fopen() / fwrite() / fclose()):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
| class T { FILE * m_pcOutFile; public: T (const char *); ~T (void); void VWrite (const char *); }; // Constructor T::T (const char * pszPath) : m_pcOutFile (fopen (pszPath, "wb")) { if (m_pcOutFile == NULL) throw 0; } // Destructor T::~T (void) { if (fclose (m_pcOutFile) != 0) throw 0; } // Writer void T::VWrite (const char * pszData) { if (fwrite (pszData, strlen(pszData), 1, m_pcOutFile) != 1) throw 0; // disk full? drive lost? fs currupt? whatever... } int main (void) { try { T t ("test"); t.VWrite ("Hello world"); } catch (...) { std::cout << "Exception caught" << std::endl; } std::cout << "End of program." << std::endl; return 0; } |
Indien tijdens uitvoering van regel 43 een exception gethrowd wordt, dan zou de situatie kunnen ontstaan dat er tijdens de afhandeling daarvan door de code op regel 25 een tweede exception gethrowd wordt, met een onbedoelde program termination tot gevolg.
Om dit probleem te omzeilen, gebruik ik in dit soort situaties vaak exceptions afgeleid van het volgende type:
1
2
3
4
5
6
7
8
9
10
11
| class E { static int s_unCnt; public: E (void) { ++s_unCnt; } ~E (void) { --s_unCnt; } static int BCanThrow (void) { s_unCnt == 0; } }; int E::s_unCnt = 0; |
Regel 25 in het tweede code snipplet wordt dan vervangen door
1
| if (E::BCanThrow()) throw E(); |
Resultaat bij konsekwent gebruik is dat je niet de afhandeling van je eigen gethrowde exception in de weg gaat zitten.
Ja, ok, dat is zo.Verwijderd schreef op dinsdag 08 juli 2008 @ 10:51:
Hoe kom je daar nou bij? Je kunt op zich probleemloos een exception throwen in een destructor, het zou m.i. zelfs tragisch zijn indien dat niet mogelijk zou zijn.
Wat fout afloopt is het throwen van een exception tijdens de afhandeling van een andere exception. Voorbeeld:
Dit is imho een slechtprogrammeervoorbeeld. Dit gaat hard mis indien iets toevallig een keer een std::exception throwed, of gewoon een heel eigen type in een library oid. Het gaat mis bij geheugen allocatie op de heap, vooral bij arrays op de heap, en mensen verwachten dat een dtor niet throwed. Ik snap ook niet waarom mensen toch altijd maar weer per se ingewikkelde constructies willen maken om toch exceptions in een dtor te throwen.Om dit probleem te omzeilen, gebruik ik in dit soort situaties vaak exceptions afgeleid van het volgende type:
Tragisch? Destructors should never throw! Het geeft meer problemen dan voordelen. Als je een delete aanroept op een object die throwt in z'n destructor, dan leak je bijvoorbeeld geheugen.Verwijderd schreef op dinsdag 08 juli 2008 @ 10:51:
[...]
Hoe kom je daar nou bij? Je kunt op zich probleemloos een exception throwen in een destructor, het zou m.i. zelfs tragisch zijn indien dat niet mogelijk zou zijn.
Met als gevolg dat als je jouw progamma merged met die van een ander die iets soortgelijks doet, dan werkt het al niet meer. Kun je beter uncaught_exception() gebruiken. Nog beter throw je gewoon niet in de destructor - het object is toch weg dus over het algemeen ben je niet eens geïnteresseerd in een eventuele foutmelding.Regel 25 in het tweede code snipplet wordt dan vervangen door
C++:
1 if (E::BCanThrow()) throw E();
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| class T{ public: T() {} ~T() {throw 0;} int data[1024]; }; int main(int argc, char* argv[]) { while (1) { try { T* t = new T(); delete t; } catch (...) {} } return 0; } |
Verwijderd
Goto's are evil!.oisyn schreef op dinsdag 08 juli 2008 @ 11:23:
[...]
Tragisch? Destructors should never throw! Het geeft meer problemen dan voordelen. Als je een delete aanroept op een object die throwt in z'n destructor, dan leak je bijvoorbeeld geheugen.
Dus: oneens. Als ik in een destructor een exception throw, dan heb ik nagedacht over de consequenties, en is het dus een zeer bewuste keuze. Zie ook verderop.
Uiteraard, je hebt helemaal gelijk. Echter, het ging mij in mijn vorige post om een strategie. Dat die strategie niet per definitie braindead universeel kompleet safe bruikbaar is, is imho géén reden om die strategie a priori af te branden. Wel eens van 'het kind met het badwater weggooien' gehoord? Niet elk programma gebruikt meer dan één base-type exception, dus het is niet per definitie onveilig.[...]
Met als gevolg dat als je jouw progamma merged met die van een ander die iets soortgelijks doet, dan werkt het al niet meer. Kun je beter uncaught_exception() gebruiken. Nog beter throw je gewoon niet in de destructor - het object is toch weg dus over het algemeen ben je niet eens geïnteresseerd in een eventuele foutmelding.
Het leek ondergetekende dermate triviaal dat wanneer je zo'n strategie gebruikt naast andere exceptions, je die andere exceptions ook af dient te vangen, dat ik dat in mijn vorige post niet heb meegenomen. Ik realiseer me dat ik dat voor de duidelijkheid beter wel had kunnen vermelden.
Bedenk echter wel terdege dat wanneer jij in een destructor van een open/close-type wrapper class een fclose() doet, en die mislukt - bijvoorbeeld ten gevolge van een disk-full situatie, en jij gooit geen exception, zet geen globale flag, en doet niet iets vergelijkbaars, dan zul jij bijvoorbeeld een tijdens de fclose() mislukte flush niet op het moment van optreden, of mogelijk nog veel erger: zelfs helemaal niet, signaleren. De enige mogelijkheid die jij dan hebt, is een fclose() expliciet aanroepen via een public member. Waarmee je het belangrijkste idee van de class, namelijk het tijdens de afhandeling van een exception impliciet afsluiten van de file, onmogelijk maakt. En je never zeker weet of je na de close niet met een corrupte - want te korte - file zit. De direkte implicatie is dat óf je class niet exception-safe is, óf je gaat buiten je class knoeien om een tekortkoming in je strategie recht te knutselen. En dat vind ik op mijn beurt in beginsel geen goed idee, omdat je dan het idee van encapsulation overboord gooit...Conditional-throwing vind ik dan absoluut een geschikt idee. Uiteraard is het wel noodzakelijk dat je erg goed nadenkt over je exceptions model, om op het juiste moment een geschikte recovery te kunnen uitvoeren.
En wat dat memory-leak betreft:
1) je hóeft een object niet met new te alloceren, je kunt het ook op de stack zetten;
2) als je het zou willlen: het is perfect mogelijk een simpele GC te maken die dat bewuste potentiële leak op een geschikt moment alsnog opruimt. Maar ik denk dat de diskussie daarover buiten de scope van dit topic valt.
Ter illustratie: ik heb hier bijvoorbeeld een lib liggen met wrappers om een flink deel van de WIN32 API. ELKE zo ongeveer niet OS-dodelijke exception die ik überhaupt af wil vangen, vang ik ook af, en wrap die om een van mijn eigen exception types. Een flink aantal van die wrappers zijn classes die kunnen throwen in hun destructors, en maken gebruik van zo'n throw-counter. Dit werkt naar volle tevredenheid, en is simpelweg veilig op de manier waarop het hier gebruikt wordt. Als een applicatie-programmeur dan besluit e.e.a. te mixen met andere libraries die andere exception-types kunnen throwen, dan is het logisch dat hij/zij daar inderdaad rekening mee zal moeten houden. Maar dat maakt mijn library nog niet meteen onbruikbaar of zelfs evil!
Verwijderd
Ik neem aan dat je bedoelt:Zoijar schreef op dinsdag 08 juli 2008 @ 11:17:
Dit gaat hard mis indien iets toevallig een keer een std::exception throwed
Anders is er namelijk helemaal niets aan de hand.Dit gaat hard mis indien regel 25 een exception gooit terwijl iets toevallig een keer een std::exception heeft gethrowed die op dat moment afgehandeld wordt
Ter illustratie van mijn manier van werken, wil ik een analogie geven: je gaat een hovenier toch ook niet verbieden een kettingzaag te gebruiken omdat zo'n stuk gereedschap bij verkeerd gebruik forse problemen op kan leveren? Nee, zo'n ding kan uitermate nuttig zijn. Wel houd je natuurlijk terdege rekening met de eigenschappen ervan.
Of C verbieden omdat je het volgende kan doen:
1
2
3
4
5
| char * F (void) { char buf[32]; return buf; } |
Het feit dat je zoiets kunt doen, maakt het returnen van een char * vanuit een functie toch niet meteen per definitie een onbruikbaar concept? Of zelfs C onbruikbaar?
Ik denk dat de volgende vraag belangrijk is: welke mensen bedoel je eigenlijk?mensen verwachten dat een dtor niet throwed.
Vergeet niet dat C++ (mede vanwege de basis 'C') van origine een taal is die niet als doelstelling heeft om probleemloos door elke beginner met succes gebruikt te kunnen worden in grotere projecten, maar een taal voor programmeurs met ervaring - die dus weten waar ze mee bezig zijn. Ik denk te kunnen stellen dat mensen die professioneel met C++ bezig zijn, zich hiervan bewust (dienen te) zijn. En dus wel degelijk moeten kunnen verwachten dat dit soort zaken kunnen spelen. En mede daarom defensief programmeren.
Nogmaals: mijn punt is dat imho dit soort dingen niet meteen afgebrand moet worden omdat niet elke programmeur meteen ziet dat het problemen op kan leveren. Al je dat gaat doen, dan kun je bijvoorbeeld net zo goed het singleton-pattern overboord gooien, omdat er mt-omgevingen zijn die geen atomaire counter set / increment / decrement hebben, of niet 100% threadsafe critical sections of zelfs semaforen kunnen creëren... Absoluut met alle respect: je gaat ook niet als overheid een wet uitbrengen die het vermogen van een kettingzaag limiteert, omdat er ook niet-profs mee werken?
Terzijde: zo ingewikkeld is een enkele uitstekend gedocumenteerde persistent flag toch niet?
Ik geloof dat ik should zei, niet must. Ben je het er dan nog steeds mee oneens?Verwijderd schreef op dinsdag 08 juli 2008 @ 13:56:
Dus: oneens
Niemand had het erover dat je je foutafhandeling niet fatsoenlijk hoeft te implementeren, in destructors of anderzijds. De discussie ging om het gooien van exceptions vanuit de destructor.Bedenk echter wel terdege dat wanneer jij in een destructor van een open/close-type wrapper class een fclose() doet, en die mislukt - bijvoorbeeld ten gevolge van een disk-full situatie, en jij gooit geen exception, zet geen globale flag, en doet niet iets vergelijkbaars, dan zul jij bijvoorbeeld een tijdens de fclose() mislukte flush niet op het moment van optreden, of mogelijk nog veel erger: zelfs helemaal niet, signaleren.
Je voorbeeld is wel aardig. Want wat ga je nu doen met de kennis dat T een exception heeft gegooid tijdens het sluiten van de stream? T is weg. De data is weg. Je kan het alleen ter kennisgeving aannemen. Als je het dus in de eerste plaats al fatsoenlijk af wilt kunnen handelen, dan zul je moeten zorgen dat je een flush doet voordat je object gedestruct wordt, zodat je passende maatregelen kan nemen. En als je object wordt gedestruct ten gevolgen van een andere exceptie, waardoor je het throwen dan maar laat, dan gaat de fout alsnog aan je neus voorbij, waardoor je dus sowieso min of meer gedwongen wordt om iets meer te doen in de destructor (of daarvoor) dan het gooien van een exception, met als gevolg dat die exception in zichzelf al vrij nutteloos wordt.
Het is imho al een beetje een broken concept dat je nog allemaal zinvolle dingen gaat zitten doen in opruim-code, waar je dan evt. nog op wilt reageren.
Echter als ik jouw object als member van mijn object definieer, ik mijn object ook ineens niet meer kan newen zonder potentieel te leaken. Het ripplet dus nogal door in je hele applicatie.1) je hóeft een object niet met new te alloceren, je kunt het ook op de stack zetten;
Perfect zou ik het niet willen noemen, en dat het mogelijk is wil nog niet meteen zeggen dat dat dan ook maar een goed idee is2) als je het zou willlen: het is perfect mogelijk een simpele GC te maken die dat bewuste potentiële leak op een geschikt moment alsnog opruimt. Maar ik denk dat de diskussie daarover buiten de scope van dit topic valt.
Ik snap nog steeds niet waarom je je eigen counter verdedigt terwijl het gebruik van de standaard functie uncaught_exception() het wél "veilig" maakt met andere libraries. Naast het feit dat ik je design gewoon flawed vind, of het voor jou nou werkt of nietTer illustratie: ik heb hier bijvoorbeeld een lib liggen met wrappers om een flink deel van de WIN32 API. ELKE zo ongeveer niet OS-dodelijke exception die ik überhaupt af wil vangen, vang ik ook af, en wrap die om een van mijn eigen exception types. Een flink aantal van die wrappers zijn classes die kunnen throwen in hun destructors, en maken gebruik van zo'n throw-counter. Dit werkt naar volle tevredenheid, en is simpelweg veilig op de manier waarop het hier gebruikt wordt. Als een applicatie-programmeur dan besluit e.e.a. te mixen met andere libraries die andere exception-types kunnen throwen, dan is het logisch dat hij/zij daar inderdaad rekening mee zal moeten houden. Maar dat maakt mijn library nog niet meteen onbruikbaar of zelfs evil!.
Het grappige hierbij is wel dat het gros van de professionele C++ programmeurs, inclusief een aantal in het C++ committee, van mening zijn dat een dtor nooit moet throwen (over defensief programmeren gesprokenIk denk te kunnen stellen dat mensen die professioneel met C++ bezig zijn, zich hiervan bewust (dienen te) zijn. En dus wel degelijk moeten kunnen verwachten dat dit soort zaken kunnen spelen. En mede daarom defensief programmeren.
I understand that some people might feel that "a failed dtor during stack unwinding is preferable in certain cases" (e.g., when recovery can be done beyond the scope of the program), but the problem is "says who?" It is the application program that should be able to decide whether or not such semantics are correct for it, and the problem here is that with the status quo a program cannot defend itself against a std::terminate() — period. The lower-level code makes the decision for everyone. In the original example, the mere existence of an XY object puts at risk every program that uses it, whether std::terminate() makes sense for that program or not, and there is no way for a program to protect itself.
That the "it's okay if the process goes south should a rare combination of things happen" decision should be made by lower-level code (e.g., X dtor) for all apps that use it, and which doesn't even understand the context of any of the hundreds of apps that use it, just cannot be correct.
[ Voor 17% gewijzigd door .oisyn op 08-07-2008 22:26 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Je zet veilig al tussen aanhalingstekens maar ik wil toch even duidelijk maken dat uncaught_exception() ook nogal wat haken en ogen heeft..oisyn schreef op dinsdag 08 juli 2008 @ 14:29:
Ik snap nog steeds niet waarom je je eigen counter verdedigt terwijl het gebruik van de standaard functie uncaught_exception() het wél "veilig" maakt met andere libraries.
Er is overigens ook een case waarin uncaught_exception() en een exception counter zoals geïmplementeerd door hij weldegelijk verschillen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| int main() { try { // code die een E throwt } catch(E & e) { /* uncaught_exception() geeft hier false, een dtor mag hier throwen. E::BCanThrow() geeft hier echter ook false, want 'e' is nog niet gedestruct dus de counter staat nog niet op 0. */ } } |
Dit hele "de ene keer wel, maar soms ook niet" maakt het imho een beetje warrig en, idd, unsound. Beter throw je gewoon helemaal niet vanuit destructors.
[ Voor 61% gewijzigd door .oisyn op 08-07-2008 22:29 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Nou, ik bedoelde eigenlijk dit:Verwijderd schreef op dinsdag 08 juli 2008 @ 14:20:
Ik neem aan dat je bedoelt:
Anders is er namelijk helemaal niets aan de hand.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| class E { public: static int count; E() {++count; std::cout << "E() count = " << count << std::endl;} ~E() {--count; std::cout << "~E() count = " << count << std::endl;} E(const E& src) {count++;} E& operator=(const E& src) {} static bool canThrow() { std::cout << "canthrow = " << count << std::endl; return count == 0; } }; int E::count = 0; class T{ public: T() {} ~T() { if (E::canThrow()) throw E(); } int data[1024]; }; int main(int argc, char* argv[]) { try { T t; // use your object // do stuff // oops, something goes wrong in my code throw std::exception("Just a minor issue; ignore"); } catch (...) { std::cout << "Exception caught" << std::endl; } std::cout << "Program ends" << std::endl; return 0; |
dat terminate.
Zo'n beetje de gehele C++ community. Throwing dtor is not-done. Het geeft te veel problemen, terwijl het niets oplevert. Je weet namelijk nog steeds niets met jouw methode: waren het 1 of 2 exceptions?Ik denk dat de volgende vraag belangrijk is: welke mensen bedoel je eigenlijk?
Precies. En daarom kan je dus wel throwen uit een dtor, maar zou je het nooit moeten doen.Vergeet niet dat C++ (mede vanwege de basis 'C') van origine een taal is die niet als doelstelling heeft om probleemloos door elke beginner met succes gebruikt te kunnen worden in grotere projecten, maar een taal voor programmeurs met ervaring - die dus weten waar ze mee bezig zijn. Ik denk te kunnen stellen dat mensen die professioneel met C++ bezig zijn, zich hiervan bewust (dienen te) zijn. En dus wel degelijk moeten kunnen verwachten dat dit soort zaken kunnen spelen. En mede daarom defensief programmeren.
Het kan op zo veel manieren mis gaan dat het het niet waard is. Wat is dat nou voor een restrictie dat ik je objecten niet op de heap mag alloceren? Je kan wel een garbage-collector schrijven (omdat je uit een dtor wilt throwen...) maar dan nog resulteert dit:Terzijde: zo ingewikkeld is een enkele uitstekend gedocumenteerde persistent flag toch niet?
1
2
| T* t = new T[5]; delete[] t; |
met jouw systeem in undefined behaviour. Er is geen garantie hoeveel objecten er hier destroyed (dtor aangeroepen) worden.
.edit: nee, ik vergis me. Het is weldegelijk UB.
15.2
Het staat er niet bij wat er gebeurt bij een exception vanuit een dtor in een array. Dus UB.15.2 Constructors and destructors
1 As control passes from a throw-expression to a handler, destructors are invoked for all automatic objects constructed since the try block was entered. The automatic objects are destroyed in the reverse order of the completion of their construction.
2 An object that is partially constructed or partially destroyed will have destructors executed for all of its fully constructed subobjects, that is, for subobjects for which the constructor has completed execution and the destructor has not yet begun execution. Should a constructor for an element of an automatic array throw an exception, only the constructed elements of that array will be destroyed. If the object or array was allocated in a new-expression, the matching deallocation function (3.7.3.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.
3 The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.” [Note: If a destructor called during stack unwinding exits with an exception, terminate is called (15.5.1). So destructors should generally catch exceptions and not let them propagate out of the destructor. —end note]
[ Voor 88% gewijzigd door .oisyn op 08-07-2008 15:31 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Na dit te typen bedenk ik me nog een flaw: je mag die throwing dtor objecten ook niet in STL containers opslaan. De erase calls van de STL gebruiken allocators, en die ruimen objecten op door expliciet de dtor aan te roepen, en dan het geheugen te dealloceren. Als die dtor throwed gaat het ook mis.
Je argumenten kun je ook toepassen wanneer een ctor throwt in een array; daar is het echter wel gewoon goed geregeld (het destruct alle geconstructe elementen en geeft het geheugen weer vrij). Ook moet de delete sowieso weten in welke volgorde de objecten zijn geconstruct, omdat hij ze in omgekeerde volgorde moet destructen. Hij kan dus exceptions vangen tijdens destructen, en bij een exception de rest nog destructen.Dan kan je ook bedenken aan hoe de code er meestal uit ziet. [...]
Er is ook een defect report over (niet zozeer over de array case, maar wel het deleten van een object met throwing dtor): http://www.open-std.org/j.../docs/cwg_active.html#265. Het probleem is niet zozeer dat het niet kan, maar dat het een performance-implicatie heeft omdat je niet altijd van tevoren kan weten of een dtor throwt (waardoor je in essentie altijd een impliciete try/catch om elke delete krijgt), waardoor je een performance penalty betaalt voor mogelijke situaties die sowieso al bad practice zijn.
[ Voor 12% gewijzigd door .oisyn op 08-07-2008 20:50 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Logisch gezien is het wel anders. Bij construction kan je gewoon alles netjes constructen en als er een fout optreedt dan destruct je alles dat je al had opgebouwd (moet uiteraard niet je dtor throwen tijdens het opruimen...). Dat kan je vrij simpel implementeren. Bij destruction zou je een eventuele fout tijdelijk op moeten slaan, verder gaan met destructen, eventuele andere fouten ook op moeten slaan, en dan aan het einde kiezen welke van die fouten je naar je applicatie throwed. Dat werkt niet makkelijk. (ie. destruction zou meerdere exception kunnen/moeten throwen, terwijl constructie er altijd maximaal eentje kan throwen) Plus dat die checks idd tijd kosten, zoals jij net zei..oisyn schreef op dinsdag 08 juli 2008 @ 20:26:
Je argumenten kun je ook toepassen wanneer een ctor throwt in een array; daar is het echter wel gewoon goed geregeld (het destruct alle geconstructe elementen en geeft het geheugen weer vrij).
[ Voor 6% gewijzigd door Zoijar op 08-07-2008 20:41 ]
Onzin natuurlijk, hij hoeft maar 1 exception te bewaren. Bij de volgende krijg je toch een terminate()Bij destruction zou je een eventuele fout tijdelijk op moeten slaan, verder gaan met destructen, eventuele andere fouten ook op moeten slaan, en dan aan het einde kiezen welke van die fouten je naar je applicatie throwed
Dus in de vorm van:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| T * t = new T[5]; int i; try { for (i = 0; i < 5; i++) t[i].~T(); operator delete[](t); } catch(...) { for (i++; i < 5; i++) t[i].~T(); operator delete[](t); throw; } |
(met natuurlijk het subtiele verschil dat uncaught_exception() in het catch blok wel true moet zijn en nog een exception zorgt voor een terminate())
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
.oisyn schreef op dinsdag 08 juli 2008 @ 11:23:
Destructors should never throw!
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Verwijderd
1
2
3
4
5
6
7
| if(masterEntry.getKey().equals(slaveEntry.getKey())) { if(!modifiedInRange(masterEntry.getModified(), slaveEntry.getModified(), timeLimit)); { System.out.println("> " + masterEntry.getKey()); } } |
https://niels.nu
Dat je compiler geen warning geeft vind ik wel een beetje suf.
Ik kwam ooit zo'n constructie tegen:
1
2
3
4
5
| if (conditie1) if (conditie2) doeIets();; else doeIetsAnders(); |

.edit: nee, m'n geheugen klopt niet, het was anders. Dit compileert sowieso niet.
[ Voor 70% gewijzigd door .oisyn op 11-07-2008 16:16 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

[edit]
De punt-komma na de if() natuurlijk.
[ Voor 58% gewijzigd door AtleX op 11-07-2008 16:06 ]
Sole survivor of the Chicxulub asteroid impact.
; na de 2e if?
/me heeft eindelijk ook een icoontje.. woef.. boeien..
Ik denk heus wel na over alle suggesties hoor; het is niet zo dat ik bij voorbaat al zeker van m'n gelijk ben. Ik heb je code zelfs compiled en getest, maar het werkt gewoon niet goed. Tot nu toe heb ik nog steeds geen goed argument gezien om throwing dtors te gebruiken, en wel op een veilige manier. Ik raad je daarom ook nog steeds aan die code die je postte niet te gebruiken: het is niet veilig.Verwijderd schreef op dinsdag 08 juli 2008 @ 23:26:
Jammer, maar met name vanwege je bovenstaande post laat ik het hierbij. De reply die ik aan het voorbereiden was, besloeg al tegen de 300 regels, maar ik begin te vermoeden dat verdere uitwerking en het posten ervan vanwege een fundamenteel perceptie-verschil dat verder gaat dan het onderwerp van diskussie, niet bijster zinvol is. Hiermee is meteen mijn probleem dat ik na die post wel eens als topic-kaper gezien zou kunnen worden, verdwenen. Iig bedankt voor de moeite die jij en Zoijar genomen hebben, en tot een volgende keer dan maar.
Dat vond ik dus ook. Op 1920x1200 zie je die puntkomma's nauwelijks. Pas toen ik dat stuk code teruggebracht had naar if(false); {} en hij nog steeds het stuk tussen accolades uitvoerde viel me opeens op dat er een puntkomma stond. Een collega zag 'em ook niet..oisyn schreef op vrijdag 11 juli 2008 @ 16:02:
Dat je compiler geen warning geeft vind ik wel een beetje suf.
Tja. Vrijdagen
https://niels.nu
Dit topic is gesloten.
Uiteraard is het in dit topic niet de bedoeling dat andere users en/of topics aangehaald worden om ze voor gek te zetten. Lachen om je eigen code, of over dingen die je "wel eens tegengekomen bent" is prima, maar hou het onderling netjes.
