Was tun wenns nix zu löschen gibt?
-
Morgen,
Sagen wir ich habe eine Klasse, die eine Collection (vector oder sonstwas) hat. Die Klasse bietet jetzt eine Methode an, um ein Element aus der Collection zu löschen, also z.B. sowas:
void Klasse::removeItem(Item item);Meine Frage ist nun: Was mache ich, wenn das item NICHT in der Collection ist? Mache ich am besten garnichts, oder soll removeItem() einen bool zurückgeben, ob das Element gefunden und damit gelöscht wurde oder soll ich eine ItemNotFound Exception werfen?
-
Am besten bool zurückgeben.
Wenn es für den Benutzer wichtig ist, ob das Objekt tatsächlich vorhanden war, kann er es so leicht überprüfen.
Und wenn es ihn nicht interessiert, hat er auch keine Lust, dafür extra eine Exception abzufangen (ich jedenfalls nicht).
-
nichts zurückgeben.
Derjenige, der diese Funktion aufruft will, dass ein bestimmtes Item danach nicht (mehr) drin ist. Und das ist der Fall
sollte er wirklich wissen wollen, ob es auch drin ist, kannst du ja eine
contains( Item item )-Schnittstelle anbieten
-
nichts zurückgeben und mit assert festlegen, daß es vorhrt drin gewesen sein muß. das fischt am meisten programmierfehler an anderen stellen raus. willst du dennoch sachen wie den boolliefernden vielleichtlöscher, biete sie ruhig an, aber mit längerem namen.
-
Es kommt wohl darauf an, welche Bedeutung man removeItem() zumisst: Dass item nach dem Aufruf nicht mehr in der Collection ist oder dass der Aufruf tatsächlich eine Löschung durchgeführt hat.
Meist handle ich nach der ersten Variante, Hauptsache, item ist nachher nicht mehr drin. Selten finde ich den Löschvorgang an sich wichtig. Warum soll man mit assert() das Programm beenden, falls item nicht in der Collection ist? Die Postcondition kann doch eingehalten werden!
Stefan.
-
DStefan schrieb:
Es kommt wohl darauf an, welche Bedeutung man removeItem() zumisst: Dass item nach dem Aufruf nicht mehr in der Collection ist oder dass der Aufruf tatsächlich eine Löschung durchgeführt hat.
Meist handle ich nach der ersten Variante, Hauptsache, item ist nachher nicht mehr drin. Selten finde ich den Löschvorgang an sich wichtig. Warum soll man mit assert() das Programm beenden, falls item nicht in der Collection ist? Die Postcondition kann doch eingehalten werden!
ich wiederhole mich gern:
das fischt am meisten programmierfehler an anderen stellen raus.
-
Ich muss volkard grundsätzlich Recht geben: ASSERT(containsItem(item)); wird vermutlich am meisten Fehler aufdecken. Bzw. ob ASSERT() oder Exception ist wohl eine Streitfrage. Eigentlich gehört da IMO eher eine Exception her.
Andrerseits finde ich die "bool" Variante am praktischsten.
Auf keine Fall würde ich eine "void" Funktion wollen, die dann aber den Fall einfach ignoriert, dass ein Element garnicht vorhanden war.
Notfalls würde ich mich an der jeweiligen Standard-Library orientieren. In dem Fall also an der C++ Standard-Library. Wenn wir uns hier std::set<T>::erase(T const&) ansehen, das liefert die Anzahl der gelöschten Elemente zurück. -> also eher bool.
(Sich an der Standard-Library zu orientieren macht IMO oft Sinn, da der User-Programmierer die Standard-Library kennen sollte. Und sich vermutlich schneller in einer neuen Library zurechtfindet, wenn Dinge gleich oder ähnlich gelöst sind, wie in der Standard-Library.)
-
hustbaer schrieb:
Notfalls würde ich mich an der jeweiligen Standard-Library orientieren. In dem Fall also an der C++ Standard-Library. Wenn wir uns hier std::set<T>::erase(T const&) ansehen, das liefert die Anzahl der gelöschten Elemente zurück. -> also eher bool.
oder list::remove, das void zurückgibt
Ich sehe keinen Grund für einen Rückgabewert. Den würde ich für nötig finden, um dem User zu sagen, das etwas nicht so sein könnte, wie er es erwartet. Aber das ist hier nicht der Fall
wenn du natürlich erlauben willst, das ganze während des "durchiterierens" zu ermöglichen, wär die Rückgabe des nächsten Iterators evtl auch möglich (siehe list::erase)
bool bringt nichts. Wenn der User wissen will, ob ein Item drin ist, kann er auch
containsaufrufen
-
Ich finde es nicht nachvollziehbar, dass der Versuch, ein nicht existierendes Element zu löschen als Fehler gewertet werden soll. Ganz gleich ob mit assert() oder Exception. Wie kommt ihr darauf, dass dies ein "Programmierfehler" ist? Ich meine ihr definiert das einfach, und diese Festlegung finde ich fragwürdig.
Es sind doch Anwendungsfälle denkbar, wo man im Programm nicht weiß, ob ein Element (noch) im Container ist. Würde nun eine Exception geworfen, müsste man in diesem Fällen vor jedem removeItem() erst einmal ein containsItem() aufrufen. Falls containsItem() true liefert, käme das Remove. Beide Funktionen aber machen est einmal eine Suche nach dem Item. Fazit: Durch die Definition des Löschversuchs eines nicht existierenden Items als Fehler, verdoppelt ihr den Aufwand beim Löschen, falls nicht bekannt ist, ob das Item vorhanden ist!
Ich finde es gut, sich in Designfragen an der STL zu orientieren. Aus den genannten Gründen. Hier findet man aber map::erase(const Key &) und set::erase(const T &), die meines Wissesns beide den Aufruf ignorieren, falls das gewünschte Element nicht vorhanden ist.
Stefan.
-
Es gibt drei Szenarien, von denen besonders die ersten beiden recht oft vorkommen:
1. Ich möchte ein Element aus dem Container löschen, von dem ich erwarte, dass es sich darin befindet. Wenn dem nicht so ist, dann existiert irgendwo ein grober Logikfehler im Programm.
2. Ich weiss, dass das Element evtl. nicht im Container ist und möchte lediglich, dass es nach der Operation garantiert nicht mehr drin ist.
3. Ich weiss, dass das Element evtl. nicht im Container ist und möchte, dass je nach Fall nach dem Löschen unterschiedlicher Code ausgeführt wird.In ersterem Fall schreibe ich
bool success=blubb.remove(bla); assert(success);im zweiten Fall kann ich den Rückgabewert ganz ignorieren, im dritten Fall kann ich
if (blubb.remove(bla)) { //... } else {}schreiben.
Der remove-Funktion einen Rückgabewert zu verpassen, bringt keine Nachteile mit sich, weder in Performance noch Usability.
Lässt sich mit contains notfalls alles auch ohne erledigen, aber das ist ein eher unschöner Notbehelf, der zudem erfordert, dass der Container ein zweites Mal durchforstet wird, was je nach Containerart und -größe zusätzliche Kosten verursacht - und zwar leicht zu vermeidende Kosten.Für den ersten Fall kann man eine Funktion à la removeExisting() anbieten. Dort (und nur dort) kann man eine ItemNotFound-Exception werfen lassen.
-
Nanyuki schrieb:
Für den ersten Fall kann man eine Funktion à la removeExisting() anbieten. Dort (und nur dort) kann man eine ItemNotFound-Exception werfen lassen.
Für mich ist halt der erste Fall der Normalfall und der boolliefernde Vielleichtlöscher ist die Kür. Vielleicht sind meine Objekte wohlerzogener und gammeln nicht dauernd in Containern rum, wo sie nicht reingehören. Naja, wenn sie fremdgehen schneide ich ihnen mit assert aber auch den Kopf ab. Und natürlich assert und keine Exception bei Logikfehler.
-
DStefan schrieb:
Ich finde es nicht nachvollziehbar, dass der Versuch, ein nicht existierendes Element zu löschen als Fehler gewertet werden soll. Ganz gleich ob mit assert() oder Exception. Wie kommt ihr darauf, dass dies ein "Programmierfehler" ist? Ich meine ihr definiert das einfach, und diese Festlegung finde ich fragwürdig.
Da "wir" in diesem Fall die Rolle des Library-Designers übernehmen, können "wir" das einfach so entscheiden.
Wenn die Library sagt "du darst erase() nur für Elemente aufrufen die auch wirklich drinnen sind", dann ist es eben ein Programmierfehler, erase() mit Elementen aufzurufen die nicht drinnen sind.
Du, der du aus der Rolle des User-Programmierers argumentierst, musst dich einfach damit abfinden - das ist in der Realität auch nicht anders. Oder verbringst du deine Tage und Nächte damit, gewisse Dinge in gewissen Libraries fragwürdig zu finden, und dich darüber aufzuregen dass es anders besser gewesen wäre?
Natürlich sollte man als Library-Designers Vor- und Nachteile der verschiedenen Möglichkeiten abwägen, und nicht willkürlich irgendwas wählen. Genau das passiert in diesem Thread, in Form dieser Diskussion. Was passt dir nun bitte daran nicht?
Was der Vorteil der "assert(vorhanden)" Variante ist kann ich dir sagen: es führt dazu, dass der User-Programmierer darüber nachdenken muss, was es denn nun bedeutet, wenn er an einer bestimmten Stelle was löschen will, was garnicht da ist. Nämlich spätestens dann, wenn das assert() das erste mal fliegt. Und wie dieser Fall korrekt zu behandeln ist. Und das vermeidet oft Programmierfehler.
Ignoriert die Funktion den Fall einfach, wird er nicht gezwungen darüber nachzudenken. Otto-Normal-User-Programmierer wird dann auch nicht weiter darüber nachdenken. In einigen Fällen wird aber "einfach ignorieren" nicht korrekt sein. Und das nennt man dann einen Fehler. Nen?
Es sind doch Anwendungsfälle denkbar, wo man im Programm nicht weiß, ob ein Element (noch) im Container ist. Würde nun eine Exception geworfen, müsste man in diesem Fällen vor jedem removeItem() erst einmal ein containsItem() aufrufen. Falls containsItem() true liefert, käme das Remove. Beide Funktionen aber machen est einmal eine Suche nach dem Item. Fazit: Durch die Definition des Löschversuchs eines nicht existierenden Items als Fehler, verdoppelt ihr den Aufwand beim Löschen, falls nicht bekannt ist, ob das Item vorhanden ist!
Man kann auch find() verwenden, welches im Fall "nicht vorhanden" einfach end() zurückliefert, und sonst einen Iterator auf das gefundene Element. So kann man dann ohne verdoppeltem Aufwand das Element löschen, nämlich indem man den Iterator an die erase() Funktion übergibt.
-
zwutz schrieb:
hustbaer schrieb:
Notfalls würde ich mich an der jeweiligen Standard-Library orientieren. In dem Fall also an der C++ Standard-Library. Wenn wir uns hier std::set<T>::erase(T const&) ansehen, das liefert die Anzahl der gelöschten Elemente zurück. -> also eher bool.
oder list::remove, das void zurückgibt
Ich sehe keinen Grund für einen Rückgabewert. Den würde ich für nötig finden, um dem User zu sagen, das etwas nicht so sein könnte, wie er es erwartet. Aber das ist hier nicht der Fall
wenn du natürlich erlauben willst, das ganze während des "durchiterierens" zu ermöglichen, wär die Rückgabe des nächsten Iterators evtl auch möglich (siehe list::erase)
bool bringt nichts. Wenn der User wissen will, ob ein Item drin ist, kann er auch
containsaufrufenHier bin ich entschieden anderer Meinung. Und zwar prinzipiell

Da die Information "war vorhanden oder nicht" von erase() gratis ermittelt werden kann (und muss), und das Zurückgeben auch "nicht weh tut" (ist ja ein billig zu kopierender Typ so ein bool), sollte die Info IMO auf jeden Fall zurückgegeben werden.
Es gab da ein ganz nettes Paper, IIRC von Alexander Stepanov, wo er u.A. auch beschreibt wieso man (seiner Meinung nach) keine Informationen "vernichten" sollte, die eine Funktion sowieso schon ermitteln muss. Wenn ich zuhause (wo ich den Link gespeichert hab) dran denke reich ich den Link hier nochmal nach. (War eh jmd. aus diesem Forum der den Link schonmal gepostet hat, wodurch ich auch drauf aufmerksam wurde.)
Natürlich könnte man auch weiter argumentieren dass erase() ja auch "gratis" an die Information drankommt, welches Element nun nach dem Gelöschten als nächstes "übrigbleibt", und dass diese Information auch nicht "vernichtet" werden sollte.
Hier das Für und Wieder abzuwägen (also return bool oder return Iterator) ist mir aber gerade etwas zu aufwendig -- da müsste ich echt mein Hirn einschalten, und das brauch ich grad für was anderes

-
@ hustbaer:
Meinst du zufällig das von Stepanov? Habs zwar nicht vollständig gelesen und bin mir dementsprechend auch nicht sicher, ob die von dir erwähnte Thematik dort angesprochen wird, aber das wurde hier zumindest ein paar Mal genannt.
-
hustbaer schrieb:
DStefan schrieb:
Ich finde es nicht nachvollziehbar, dass der Versuch, ein nicht existierendes Element zu löschen als Fehler gewertet werden soll. Ganz gleich ob mit assert() oder Exception. Wie kommt ihr darauf, dass dies ein "Programmierfehler" ist? Ich meine ihr definiert das einfach, und diese Festlegung finde ich fragwürdig.
Da "wir" in diesem Fall die Rolle des Library-Designers übernehmen, können "wir" das einfach so entscheiden.
Wenn die Library sagt "du darst erase() nur für Elemente aufrufen die auch wirklich drinnen sind", dann ist es eben ein Programmierfehler, erase() mit Elementen aufzurufen die nicht drinnen sind.
Du, der du aus der Rolle des User-Programmierers argumentierst, musst dich einfach damit abfinden - das ist in der Realität auch nicht anders. Oder verbringst du deine Tage und Nächte damit, gewisse Dinge in gewissen Libraries fragwürdig zu finden, und dich darüber aufzuregen dass es anders besser gewesen wäre?
Das ist ja alles ganz nett, nur beantwortet es meine Frage nicht. Wie kommt man auf den Gedanken, das Löschen eines Elements als Fehler zu werten, das nicht in der Collection vorhanden ist?
Indem ich mich gegen diese Festlegung wende, argumentiere ich keineswegs aus der Sicht des Users/Kunden. Im Gegenteil: Ich frage, warum unsere Containerklasse darauf bestehen soll, einen solchen Löschversuch als Fehler zu behandeln, wenn doch durch schlichtes Ignorieren des Aufrufs die Postcondition eingehalten werden kann. Diese Frage bleibt "innen", sie sieht sich nur den Container an, nicht den Kunden.
Hingegen die Feststellung, dass auf diese Weise "Programmierfehler" vermieden werden können: Das ist ein Argument, das nur funktioniert, wenn man von "außen", also aus der Sicht des Users argumentiert. Das Design von removeItem() ist klar und sauber, wenn nach dem Aufruf das Item nicht mehr in der Collection ist. Ganz gleich, ob es vorher drin war oder nicht. Die Argumente für eine Exception betreffen den Container überhaupt nicht, sondern nur denjenigen, der ihn einsetzt.
hustbaer schrieb:
Natürlich sollte man als Library-Designers Vor- und Nachteile der verschiedenen Möglichkeiten abwägen, und nicht willkürlich irgendwas wählen. Genau das passiert in diesem Thread, in Form dieser Diskussion. Was passt dir nun bitte daran nicht?
Genau das mache ich doch: Vor- und Nachteile abwägen. Ich diskutiere. Nur dass ich eben anderer Meinung bin als du. Hast du den Eindruck, dass ich nicht abwäge? Willkürlich wähle? Das würde mich doch sehr wundern.
hustbaer schrieb:
Was der Vorteil der "assert(vorhanden)" Variante ist kann ich dir sagen: es führt dazu, dass der User-Programmierer darüber nachdenken muss, was es denn nun bedeutet, wenn er an einer bestimmten Stelle was löschen will, was garnicht da ist. Nämlich spätestens dann, wenn das assert() das erste mal fliegt. Und wie dieser Fall korrekt zu behandeln ist. Und das vermeidet oft Programmierfehler.
Ignoriert die Funktion den Fall einfach, wird er nicht gezwungen darüber nachzudenken. Otto-Normal-User-Programmierer wird dann auch nicht weiter darüber nachdenken. In einigen Fällen wird aber "einfach ignorieren" nicht korrekt sein. Und das nennt man dann einen Fehler. Nen?
Nein! Im Ernst, was ist denn das für ein Argument? Eine Klasse verhält sich so und so (und meiner Meinung nach ohne objektiven Grund), um den Kunden zu "anständigem" Verhalten zu erziehen?!!
Erstens: Wohin führt das? Wenn ich dieses Argument ernst nehme, wie muss ich meine Klassen designen, damit sie ihm genügen? Ich müsste wohl sagen: "Ja, was du hier tun willst, dass kann meine Klasse schon tun. Aber der Kontext, in dem du das tust, die Absicht, die du verfolgst kann ich nicht gut heißen." Das ist absurd!
Zweitens: Du drängst dem Kunden des Containers hier deine Auffassung von "Programmierfehler" auf. Ich habe in einem anderen Beitrag schon geschrieben, dass dies gar nicht so ausgemachte Sache ist. Es muss nicht zwingend ein Programmierfehler sein, nicht vorhandene Items löschen zu wollen. Wenn ich removeItem() so designe, dann zwinge ich den "Programmierfehler" herbei. Und noch einmal: Ich tue das ohne Not!
hustbaer schrieb:
Man kann auch find() verwenden, welches im Fall "nicht vorhanden" einfach end() zurückliefert, und sonst einen Iterator auf das gefundene Element. So kann man dann ohne verdoppeltem Aufwand das Element löschen, nämlich indem man den Iterator an die erase() Funktion übergibt.
Klar kann man das. Aber das war hier ja nicht die Frage. Ich habe einfach das Ausgangsposting wörtlich genommen: removeItem() erhält ein Item als Parameter, keinen Iterator. Ich meine, die Diskussion, ob das sinnvoll ist, gehört in einen anderen Thread. Und würde wohl auch mehr Wissen über den Container erfordern.
Stefan.
-
Es ist doch nicht allein die Frage, ob Post/Pre-Conditions verletzt werden, wie eine Schnittstelle aussehen soll.
Fehlervermeidendes oder wenigstens fehlersuchfreundliches Design gehört zu C++ dazu und sollte in Sachen Stil auch immer eines der wichtigsten Ziele sein.
Ob der User eine Zeile mehr tippen muß, ist dagegen recht egal.
Und immer wieder bieten Klassen dies oder jenes nicht an, weil der User damit nur Mist bauen würde. Wenn ich Deinen Stil weitertreibe bekommt eine verkettete Liste einen T& operator[](size_t index).
-
volkard schrieb:
Es ist doch nicht allein die Frage, ob Post/Pre-Conditions verletzt werden, wie eine Schnittstelle aussehen soll.
Nein, es ist z.B. auch die Frage, ob eine Klassen macht, was sie soll. Eine Klasse (meine ich) soll ihre Pre- und Postconditions eisern schützen. Und sie soll das tun, was sie "sagt", dass sie tut - und damit meine ich nicht bloß die Dokumentation.
Eine Klasse soll aber nicht die Umstände kontrollieren wollen, unter denen sie eingesetzt wird. Sie muss ihre eigene Integrität wahren, aber nicht die Integrität des Programms (oder so).
Wenn mir danach wäre, auf einer std::list auch ohne op[] massenweise "Index-Zugriffe" (du weißt schon) auszuführen, was würdest du sagen? Programmierfehler? Zumindest aber Anwendungsfehler. Mein Programm funktioniert aber es ist vielleicht Scheiße langsam.
Und wenn std::list ohne großen Aufwand feststellen könnte, dass der Kunde einen Programmierfehler macht - ich weiß, ich mute deiner Vorstellungskraft einiges zu
- sollte die Collection dann eine Exception werfen?Ich denke nein. Eine solche Klasse tut nicht, was sie soll.
volkard schrieb:
Und immer wieder bieten Klassen dies oder jenes nicht an, weil der User damit nur Mist bauen würde. Wenn ich Deinen Stil weitertreibe bekommt eine verkettete Liste einen T& operator[](size_t index).
Bitte, ich habe nicht mehr Verhalten vorgeschlagen, sondern weniger. Ich wollte nicht mehr Aufwand treiben, sondern weniger.
Naja - den Rest habe ich ja schon oben gesagt.Stefan.
-
Nexus schrieb:
@ hustbaer:
Meinst du zufällig das von Stepanov?Jopp, genau das, danke!
Geht los ab Seite 134. Bzw. bei "Lecture 13. Iterators".Habs zwar nicht vollständig gelesen und bin mir dementsprechend auch nicht sicher, ob die von dir erwähnte Thematik dort angesprochen wird, aber das wurde hier zumindest ein paar Mal genannt.
Lies es (ganz)

Ich kann zwar mit einigem was er schreibt nicht wahnsinnig viel Anfangen, aber alles in allem finde ich es ziemlich gut. Wenig theoretisches lala sondern relativ schön aus der Praxis. Manchmal übertreibt er es für meinen Geschmack ein wenig, aber wenn man das so liest, bekommt man finde ich eine gute Vorstellung davon, was man so beim Thema Library-Design alles falsch oder richtig machen kann
-
hustbaer schrieb:
Lies es (ganz)

Ich kann zwar mit einigem was er schreibt nicht wahnsinnig viel Anfangen, aber alles in allem finde ich es ziemlich gut. Wenig theoretisches lala sondern relativ schön aus der Praxis. Manchmal übertreibt er es für meinen Geschmack ein wenig, aber wenn man das so liest, bekommt man finde ich eine gute Vorstellung davon, was man so beim Thema Library-Design alles falsch oder richtig machen kann
Ja, werde ich tun, danke!
Ich habe mich bisher ein wenig mit dem dort erwähnten
swap()und dem drumherum befasst, aber das ist auch schon eine Weile her. Das hat mich da sehr interessiert, aber irgendwie hab ichs wohl wieder vernachlässigt. Naja, in nächster Zeit habe ich mir sowieso vorgenommen, mich theoretisch ein wenig weiterzubilden, da kommt das gerade recht...
-
@DStefan:
Guck mal.
Erstmal vorweg: ich persönlich finde die "return bool" Variante die "beste". Nur damit wir uns nicht misverstehen. Hab ich zwar schon geschrieben, aber vielleicht hast du das ja überlesen.Davon abgesehen bin ich aber der Meinung, dass der Standpunkt "remove(gibtsNicht) == Fehler" seine Berechtigung hat.
Es ist logisch gesehen halt einfach nicht möglich, etwas zu entfernen, was nicht da ist.
Die Frage ob "remove(gibtsNicht)" "OK" ist, ist IMO äquivalent zur Frage ob "delete NULL" "OK" ist. Der C++ Standard sagt in beiden Fällen "ja, ist OK". Was aber durchaus strittig ist, in beiden Fällen (hallo volkard :)).
"delete p", wenn "p" NULL ist, ist, meiner Meinung nach, logisch betrachtet Unfug. Praktisch, aber Unfug. Warum die "Hardliner" (hallo volkard :D) argumentieren dass es verboten werden sollte: du kannst ein Objekt welches nicht existiert, nicht löschen. Der Versuch es zu tun, deutet darauf hin, dass das Programm welches es tut, nicht weiss was es tut. = Programmierfehler.
Und von diesem Standpunkt aus betrachtet, macht IMO keine andere Definition von "remove" Sinn, als die, dass es ein Fehler ist, "remove" mit einem Item aufzurufen, welches garnicht in der Collection enthalten ist.
----
Bitte, ich habe nicht mehr Verhalten vorgeschlagen, sondern weniger. Ich wollte nicht mehr Aufwand treiben, sondern weniger.
Ansichtssache. Aus Sicht der Implementierung: ja, vielleicht. Aus Sicht der Interface-Definition: nein. "Entfernt das Element x, falls es vorhanden ist" ist "mehr" als "Entfernt das Element x".
-
DStefan schrieb:
Nein, es ist z.B. auch die Frage, ob eine Klassen macht, was sie soll. Eine Klasse (meine ich) soll ihre Pre- und Postconditions eisern schützen.
Gut und hustbaer wie auch volkard sagen, dass das
Itemvorhanden sein soll, die Precondition vonRemoveItemist. Und wenn die Precondition verletzt ist, dann soll man dem User dies schliesslich mitteilen, da man die Pre- und Postconditions eisern schützen muss, nicht?
Die Frage ist halt wirklich nur, ob man diese Precondition annehmen soll oder nicht?
Und da denke ich, kommt es sehr auf die Art der Funktion an. Ist zum Beispiel Item dervalue_typeder Containerklasse, dann kann man wohl davon ausgehen, dass die Precondition nicht gilt, da diese Funktion einfach alle Vorkommnisse von diesem Item-Wert löschen soll. Ähnlich wie dies auchstd::list<Item>::removetut.
Ist RemoveItem hier allerdings zum Beispiel eine interne Funktion der Klasse (private) und Item ein Container-Element, dann sollte man wohl die Precondition schon prüfen, ob Item auch wirklich zu diesem Container gehört. Dies könnte man auch auf eine öffentliche Funktion, welche einen Iterator annimmt verwenden. Wie dies durchaus gewisse Implementationen machen, nämlich einassert(false)aufrufen, wenn man anstd::list<X>::eraseoderstd::vector<X>::erasefalsche Iteratoren übergibt.Und es gibt wohl auch noch andere Möglichkeiten, wie man diese
RemoveItemFunktion verstehen kann
Wenn man allerdings die Art wählt, dass man keine Precondition nimmt, dann würde ich auch einen entsprechenden Rückgabewert empfehlen, aus dem einfachen Grund, dass man dem User dann helfen kann, sowas zu machen:
bool result = removeItem(item); assert(!result);Eine Library soll schliesslich auch Userfreundlich sein, also diesem helfen wo es nur geht.
Grüssli