Unerlaubte Argumente anzeigen
-
tkausl schrieb:
AndreasLeeb schrieb:
Ich habe gelesen, dass man in Konstruktoren nicht unbedingt Exceptions werfen sollte, stimmt das?
Das stimmt nicht. Wenn das Object mit dem falschen Parameter nicht sinnvoll Konstruierbar ist bleibt dir nichts anderes übrig.
Ok, danke für die Antwort!
Also in solchen Fällen immer invalid_argument werfen.
-
Nein! invalid_argument ist keine gute Lösung.
Negativer Monat vermeidet man durch unsigned. Zu hoher Monat prüft man mit assert. Exceptions sind für Ausnahmefälle, nicht Logikfehler!
-
brassert schrieb:
Nein! invalid_argument ist keine gute Lösung.
Negativer Monat vermeidet man durch unsigned. Zu hoher Monat prüft man mit assert. Exceptions sind für Ausnahmefälle, nicht Logikfehler!
Ok, danke!
-
brassert schrieb:
Nein! invalid_argument ist keine gute Lösung.
Negativer Monat vermeidet man durch unsigned. Zu hoher Monat prüft man mit assert. Exceptions sind für Ausnahmefälle, nicht Logikfehler!
Pauschale Aussagen sind immer falsch.
In der Standradlib wird zwar in der Regel so verfahren, vector.at prüft aber z.B. dennoch, ob der Index gültig ist.
-
manni66 schrieb:
Pauschale Aussagen sind immer falsch.
Das war die Regel, wie man verfahren sollte und als Anfänger ist man gut damit geraten sich daran ausnahmslos zu halten.
manni66 schrieb:
In der Standradlib wird zwar in der Regel so verfahren, vector.at prüft aber z.B. dennoch, ob der Index gültig ist.
Das ist auch einzige Daseinsberechtigung von
vector::at
. Bei so allgemeinen Funktionen wie at() will man das manchmal.
-
Ich mach manchmal das hier:
struct month { month() noexcept : from_zero(0) { } static boost::optional<month> create_checked(std::uint8_t from_zero) noexcept { if (from_zero >= 12) { return boost::none; } return month(from_zero); } std::uint8_t index_from_zero() const noexcept { return from_zero; } private: std::uint8_t from_zero; explicit month(std::uint8_t from_zero) noexcept : from_zero(from_zero) { } };
-
brassert schrieb:
Nein! invalid_argument ist keine gute Lösung.
Negativer Monat vermeidet man durch unsigned. Zu hoher Monat prüft man mit assert. Exceptions sind für Ausnahmefälle, nicht Logikfehler!
brassert schrieb:
Das war die Regel, wie man verfahren sollte und als Anfänger ist man gut damit geraten sich daran ausnahmslos zu halten.
Was macht man wenn der Monat aus einer User-Eingabe kommt (bitte geben Sie ihr Geburtsdatum ein)? Dann bringt einem das Assert nix und wenn ich vor dem konstruieren prüfe hab ich den check zweimal drinnen...
-
happystudent schrieb:
brassert schrieb:
Nein! invalid_argument ist keine gute Lösung.
Negativer Monat vermeidet man durch unsigned. Zu hoher Monat prüft man mit assert. Exceptions sind für Ausnahmefälle, nicht Logikfehler!
brassert schrieb:
Das war die Regel, wie man verfahren sollte und als Anfänger ist man gut damit geraten sich daran ausnahmslos zu halten.
Was macht man wenn der Monat aus einer User-Eingabe kommt (bitte geben Sie ihr Geburtsdatum ein)? Dann bringt einem das Assert nix und wenn ich vor dem konstruieren prüfe hab ich den check zweimal drinnen...
Assert im Konstruktor und Validierung der Eingabe.
Im Release ist das Assert weg aber die Eingabe muss immer noch geprüft werden, darum muss die bestehen bleiben.
Und wenn du keine Code Duplizierung haben möchtest schreibe dir eine Validierung Funktion.bool validateMonth(std::uint8_t month) { // ... } std::uint8_t userInput = //... if (!validateMonth(userInput)) { std::cout << "Kauf dir einen Kalender!"; } struct month { month(std::uint8_t from_zero) : from_zero(from_zero) { assert(validateMonth(m)); // ... } // ... }
-
C Newbie schrieb:
happystudent schrieb:
brassert schrieb:
Nein! invalid_argument ist keine gute Lösung.
Negativer Monat vermeidet man durch unsigned. Zu hoher Monat prüft man mit assert. Exceptions sind für Ausnahmefälle, nicht Logikfehler!
brassert schrieb:
Das war die Regel, wie man verfahren sollte und als Anfänger ist man gut damit geraten sich daran ausnahmslos zu halten.
Was macht man wenn der Monat aus einer User-Eingabe kommt (bitte geben Sie ihr Geburtsdatum ein)? Dann bringt einem das Assert nix und wenn ich vor dem konstruieren prüfe hab ich den check zweimal drinnen...
Assert im Konstruktor und Validierung der Eingabe.
Im Release ist das Assert weg aber die Eingabe muss immer noch geprüft werden, darum muss die bestehen bleiben.
Und wenn du keine Code Duplizierung haben möchtest schreibe dir eine Validierung Funktion.bool validateMonth(std::uint8_t month) { // ... } std::uint8_t userInput = //... if (!validateMonth(userInput)) { std::cout << "Kauf dir einen Kalender!"; } struct month { month(std::uint8_t from_zero) : from_zero(from_zero) { assert(validateMonth(m)); // ... } // ... }
Wenn man eine validateMonth Methode macht, wie soll man dann in der Methode verfahren, wenn das Monat < 1 oder > 12 ist?
-
AndreasLeeb schrieb:
C Newbie schrieb:
happystudent schrieb:
brassert schrieb:
Nein! invalid_argument ist keine gute Lösung.
Negativer Monat vermeidet man durch unsigned. Zu hoher Monat prüft man mit assert. Exceptions sind für Ausnahmefälle, nicht Logikfehler!
brassert schrieb:
Das war die Regel, wie man verfahren sollte und als Anfänger ist man gut damit geraten sich daran ausnahmslos zu halten.
Was macht man wenn der Monat aus einer User-Eingabe kommt (bitte geben Sie ihr Geburtsdatum ein)? Dann bringt einem das Assert nix und wenn ich vor dem konstruieren prüfe hab ich den check zweimal drinnen...
Assert im Konstruktor und Validierung der Eingabe.
Im Release ist das Assert weg aber die Eingabe muss immer noch geprüft werden, darum muss die bestehen bleiben.
Und wenn du keine Code Duplizierung haben möchtest schreibe dir eine Validierung Funktion.bool validateMonth(std::uint8_t month) { // ... } std::uint8_t userInput = //... if (!validateMonth(userInput)) { std::cout << "Kauf dir einen Kalender!"; } struct month { month(std::uint8_t from_zero) : from_zero(from_zero) { assert(validateMonth(m)); // ... } // ... }
Wenn man eine validateMonth Methode macht, wie soll man dann in der Methode verfahren, wenn das Monat < 1 oder > 12 ist?
bool validateMonth(std::uint8_t month) { return month >= 1 && month <= 12; }
Die Behandlung von falschen month werten passiert natürlich beim Aufrufer.
-
Ok danke!
-
@brassert
Du hast halt deine Meinung hier presentiert als ob es ein Fakt wäre, und als ob es dazu nicht mehr zu sagen gäbe.Es gibt aber oft gute Gründe nicht "garbage in garbage out" zu machen. Was mMn. auch der Grund dafür ist dass es
vector::at
überhaupt gibt.
Und der vermutlich wichtigste Grund nicht "garbage in garbage out" zu machen ist, dass es hilft den Effekt von Fehlern einzugrenzen. Klar, Fehler sollten nicht im ausgelieferten Produkt drinnen sein. Das fehlerfreie (nicht triviale) Programm ist aber eher eine Wunschvorstellung, auf jeden Fall nichts wovon man ausgehen kann.Und dann muss man sich fragen: was ist besser, ein "garbage in garbage out" Programm das im Falle des Falles gröbstens Mist baut (z.B. alle Daten löscht), oder ein Programm das im Falle des Falles mit einer mehr oder weniger verständlichen Fehlermeldung abbricht?
Das ganze ist natürlich auch oft ein Kompromiss zwischen Sicherheit und Performance.
An Stellen wo Laufzeitprüfungen wirklich wichtig sind, istassert()
aber auf jeden Fall der falsche Weg, da im ausgelieferten Programm nix mehr davon übrig bleibt.
Wenn man den Aufrufer "dazu ermuntern will" auf seiner Seite bereits dafür zu sorgen dass alles OK ist, kann man stattassert(exp)
immer noch eine eigene Hilfsfunktion verwenden, die im Fall!exp
eine Meldung ausgibt und danachabort()
aufruft. Und die eben auch in einem Release-Build drinnen bleibt.
-
@C Newbie
Für eine Funktion die true zurückliefert wenn ihr Argument eine gültige Monatsnummer ist, istvalidateMonth
mMn. ein schlechter Name.Erstmal ist
validateXxx(arg)
nicht klar/eindeutig, es könnten mehrere Dinge damit gemeint sein. Folgende Verhalten wären denkbar:- Die Methode validiert (im Sinn von: erklärt für gültig)
arg
als xxx. z.B. indem der übergebene Wert in einer Liste gültiger xxx-Werte eingetragen wird, wo andere Funktionen dann nachgucken können ob sie ihrerseits einen gültigen xxx-Wert übergeben bekommen haben. - Die Methode selbst ist als Assertion zu verstehen, macht also intern ein
assert(arg is a valid xxx)
. - Ähnlich (2) nur dass die Methode intern ein
if (arg is NOT a valid xxx) throw ...
macht. - Die Methode prüft die Validität von
arg
und gibt danntrue
bzw.false
zurück. - Die Methode biegt
arg
so zurecht dass dabei ein gültiges xxx rauskommt. z.B. durch Clamping, Modulo-Arithmetik oder Ersetzen von ungültigen Werten mit einem Default.
Deine
validateXxx(arg)
macht jetzt (4). Und das ist doppelt schlimm, denn für (4) gibt es einen super einfachen, oft verwendeten und auch 100% unmisverständlichen anderen Namen:isValidXxx(arg)
(Und auch für (1), (2), (3) und (5) gibt es mMn. viel bessere Namen, wobei diese Fälle schon eine Spur schwieriger sind als (4))
- Die Methode validiert (im Sinn von: erklärt für gültig)
-
Was ist eigentlich an meinem Ansatz mit dem statischen Pseudokonstruktor und
optional
so schlimm, dass der gänzlich ignoriert wird?
-
TyRoXx schrieb:
Was ist eigentlich an meinem Ansatz mit dem statischen Pseudokonstruktor und
optional
so schlimm, dass der gänzlich ignoriert wird?Viel zu umständlich?
-
hustbaer schrieb:
@C Newbie
Für eine Funktion die true zurückliefert wenn ihr Argument eine gültige Monatsnummer ist, istvalidateMonth
mMn. ein schlechter Name.Erstmal ist
validateXxx(arg)
nicht klar/eindeutig, es könnten mehrere Dinge damit gemeint sein. Folgende Verhalten wären denkbar:- Die Methode validiert (im Sinn von: erklärt für gültig)
arg
als xxx. z.B. indem der übergebene Wert in einer Liste gültiger xxx-Werte eingetragen wird, wo andere Funktionen dann nachgucken können ob sie ihrerseits einen gültigen xxx-Wert übergeben bekommen haben. - Die Methode selbst ist als Assertion zu verstehen, macht also intern ein
assert(arg is a valid xxx)
. - Ähnlich (2) nur dass die Methode intern ein
if (arg is NOT a valid xxx) throw ...
macht. - Die Methode prüft die Validität von
arg
und gibt danntrue
bzw.false
zurück. - Die Methode biegt
arg
so zurecht dass dabei ein gültiges xxx rauskommt. z.B. durch Clamping, Modulo-Arithmetik oder Ersetzen von ungültigen Werten mit einem Default.
Deine
validateXxx(arg)
macht jetzt (4). Und das ist doppelt schlimm, denn für (4) gibt es einen super einfachen, oft verwendeten und auch 100% unmisverständlichen anderen Namen:isValidXxx(arg)
(Und auch für (1), (2), (3) und (5) gibt es mMn. viel bessere Namen, wobei diese Fälle schon eine Spur schwieriger sind als (4))
Ja ich gebe dir recht das ich den Name suboptimal gewählt habe,
jetzt würde mich noch interesieren welche Namen du für (1), (2), (3) und (5) nehmen würdest? (Und wie man bei der Signatur überhaupt auf (5) kommen kann )
(1) declareValid?
(2) assertValid?
(3) assureValid
(5) fitToValidValues
- Die Methode validiert (im Sinn von: erklärt für gültig)
-
markValidXxx, tagValidXxx, rememberValidXxxValue
- etwas in der Art- Ja, ganz klar
assertValidXxx
- Schwierig wenn man es von (2) abgrenzen will (was ich nicht unbedingt nötig finde). "Assure" finde ich nicht ganz passend.
requireValidXxx
vielleicht. makeValidXxx, forceValidXxx
odersubstituteInvalidXxxValues
. Bzw. auch spezifischerclampToValidXxx
odersubstituteInvalidXxxWithDefault
.
C Newbie schrieb:
(Und wie man bei der Signatur überhaupt auf (5) kommen kann )
Das ist ne gute Frage. Müsste ich denjenigen fragen der den Code wo ich es gesehen habe geschrieben hat - dummerweise arbeitet der nicht mehr bei uns. Wobei ich zugeben muss dass ich mir beim Funktionsnamen gerade nicht 100% sicher bin. Ich glaube es war
validateXxx
, kann aber auchverifyXxx
gewesen sein (was aber mMn. noch weniger Sinn machen würde).