Ich habe eine C ++ - Struktur und eine Methode:
%Vor%Ich kann eine Account-Struktur zurückgeben, wenn das Konto existiert, aber was tun, wenn es kein Konto gibt?
Ich dachte daran:
Gibt es einen besten Weg, dies zu tun?
Sie haben die offensichtlichste Version in C ++ vergessen:
%Vor% Gebe true
zurück und fülle die angegebene Referenz aus, wenn das Konto existiert, sonst gib false
zurück.
Es kann auch nützlich sein, die Tatsache zu verwenden, dass Zeiger null sein können und Folgendes haben:
%Vor% Dies könnte so definiert werden, dass true
zurückgegeben wird, wenn die Konto-ID existiert, aber nur (natürlich) um das angegebene Konto auszufüllen, wenn der Zeiger nicht null ist. Manchmal ist es praktisch, in der Lage zu sein, die Existenz zu testen, und das spart die Notwendigkeit einer dedizierten Methode nur für diesen Zweck.
Es ist eine Frage des Geschmacks, was Sie bevorzugen.
Von den gegebenen Optionen würde ich Account*
zurückgeben. Der zurückkehrende Zeiger kann jedoch einige negative Auswirkungen auf die Schnittstelle haben.
Eine andere Möglichkeit ist throw
eine Ausnahme, wenn es kein solches Konto gibt. Sie können auch boost::optional
ausprobieren.
Es hängt davon ab, wie hoch die Wahrscheinlichkeit ist, dass das Konto nicht existiert.
Wenn es wirklich außergewöhnlich ist - tief in den Tiefen des Inneren des Bankensystems, wo die Daten gültig sein sollen - dann vielleicht eine Ausnahme werfen.
Wenn es sich um eine Benutzerschnittstellenebene handelt, die Daten validiert, dann werfen Sie wahrscheinlich keine Ausnahme.
Das Zurückgeben eines Zeigers bedeutet, dass jemand den zugewiesenen Speicher freigeben muss - das ist unordentlicher.
Können Sie eine 'Marker-ID' (z. B. 0) verwenden, um 'ungültiges Konto' anzugeben?
Es gibt mehrere Methoden.
1) Wirf eine Ausnahme aus. Dies ist nützlich, wenn GetAccountById
das Konto nach Wert zurückgeben soll und die Verwendung von Ausnahmen Ihrem Programmiermodell entspricht. Einige werden Ihnen sagen, dass Ausnahmen nur in Ausnahmefällen "gemeint" sind. Dinge wie "out of memory" oder "Computer in Brand". Dies ist sehr umstritten, und für jeden Programmierer, den Sie finden, der sagt, Ausnahmen sind nicht für die Flusskontrolle, finden Sie einen anderen (mich eingeschlossen), der sagt, dass Ausnahmen für die Flusskontrolle verwendet werden können. Sie müssen darüber nachdenken und selbst entscheiden.
2) Rückgabe nicht und Account
nach Wert. Übergeben Sie stattdessen mit Zeiger (vorzugsweise intelligenter Zeiger) und geben Sie NULL zurück, wenn Sie das Konto nicht gefunden haben:
3) Zurückgeben eines Objekts, das ein 'Präsenz'-Flag hat, das angibt, ob das Datenelement vorhanden ist oder nicht. Boost.Optional ist ein Beispiel für ein solches Gerät, aber Falls Sie Boost hier nicht verwenden können, ist ein Vorlagenobjekt mit einem bool
-Member, das true
ist, wenn das Datenelement vorhanden ist, und false
, wenn dies nicht der Fall ist. Das Datenelement selbst wird im value_
-Member gespeichert. Es muss standardmäßig konstruierbar sein.
Der Einfachheit halber würde ich einen Typedef für Account
erstellen:
... und dann von der Funktion zurückgeben:
%Vor%Dies ist einfach:
%Vor% Es gibt noch einen anderen Weg, der dem "is valid" -Muster ähnlich ist. Ich entwickle gerade eine Anwendung, die eine Menge solcher Sachen enthält. Aber meine IDs können nie kleiner als 1 sein (sie sind alle SERIAL-Felder in einer PostgreSQL-Datenbank), also habe ich nur einen Standardkonstruktor für jede Struktur (oder Klasse in meinem Fall), der id
mit -1 und isValid()
method initialisiert das gibt wahr zurück, wenn id
nicht gleich -1 ist. Funktioniert perfekt für mich.
Ich würde tun:
%Vor%Eine Methode namens get sollte immer das angeforderte Objekt zurückgeben (IMHO). Wenn es nicht existiert, dann ist das eine Ausnahme. Wenn die Möglichkeit besteht, dass etwas nicht vorhanden ist, sollten Sie auch eine Find-Methode bereitstellen, die bestimmen kann, ob das Objekt existiert, damit ein Benutzer es testen kann.
%Vor%Ich hätte jetzt einen Zeiger verwenden können, anstatt mich um die Erstellung von AccountRef zu kümmern. Das Problem dabei ist, dass Zeiger keine Besitz-Symantiken haben und daher gibt es keine echte Angabe darüber, wer den Zeiger besitzen (und daher löschen) sollte.
Als ein Ergebnis mag ich es, Zeiger in einen Container zu verpacken, der es dem Benutzer erlaubt, das Objekt nur so zu manipulieren, wie ich es auch möchte. In diesem Fall stellt der AccountRef den Zeiger nicht zur Verfügung, so dass es keine Möglichkeit für den Benutzer von AccountRef gibt, das Konto tatsächlich zu versuchen und zu löschen.
Hier können Sie überprüfen, ob AccountRef gültig ist und einen Verweis auf ein Konto extrahieren (vorausgesetzt, es ist gültig). Da das Objekt nur einen Zeiger enthält, ist der Compiler wahrscheinlich, dies zu dem Punkt zu optimieren, dass dies nicht teurer ist, als den Zeiger herumzugeben. Der Vorteil ist, dass der Benutzer nicht versehentlich missbrauchen kann, was ich ihnen gegeben habe.
Zusammenfassung: AccountRef hat keine echten Laufzeitkosten. Aber bietet Typ Sicherheit (wie es die Verwendung von Zeiger versteckt).
Ich mache gerne eine Kombination aus dem, was Sie vorschlagen, mit dem Gültig-Flag und dem, was jemand anderes mit dem Null-Objektmuster vorgeschlagen hat.
Ich habe eine Basisklasse namens Status
, die ich von Objekten erhalte, die ich als Rückgabewerte verwenden möchte. Ich werde das meiste aus dieser Diskussion herauslassen, da es etwas komplizierter ist, aber es sieht ungefähr so aus.
Jetzt hättest du
%Vor%Wenn Sie jetzt ein Konto ohne Parameter erstellen:
%Vor%Es ist ungültig. Aber wenn Sie ein Konto mit Daten erstellen
%Vor%Es ist gültig.
Sie testen die Gültigkeit mit dem Operator bool.
%Vor%Ich mache das sehr oft, wenn ich mit Mathe-Typen arbeite. Ich möchte zum Beispiel keine Funktion schreiben müssen, die so aussieht.
%Vor%wobei a, b und c Matrizen sind. Ich würde viel lieber schreiben
%Vor%mit Überladung des Operators. Aber es gibt Fälle, in denen a und b nicht multipliziert werden können, so dass es nicht immer gültig ist. Sie geben einfach ein ungültiges c zurück, wenn es nicht funktioniert, und ich kann
tun %Vor%