Der beste Weg, um von einer Funktion, die eine Referenz zurückgibt, früher zurückzukommen

8

Sagen wir, wir haben eine Funktion der Form:

%Vor%

Offensichtlich hat der obige Code ein Problem, wenn die Bedingung fehlschlägt, haben wir ein Problem, wie wir von dieser Funktion zurückkehren können. Der Kern meiner Frage ist, was ist der beste Weg, um mit einer solchen Situation umzugehen?

    
Konrad 18.11.2009, 10:22
quelle

14 Antworten

24

Dies ist kein syntaktisches Problem, sondern ein Designproblem. Sie müssen angeben, was ReturnOurObject() zurückgeben soll, wenn SomeCondition wahr ist. Das hängt hauptsächlich davon ab, wofür die Funktion verwendet wird. Und das hast du uns nicht gesagt.

Je nach Designproblemen sehe ich ein paar mögliche syntaktische Möglichkeiten:

  • gibt einen Verweis auf ein anderes Objekt zurück; du müsstest irgendwo ein Ersatzobjekt haben
  • hat ein spezielles "no-object-to-return" -Objekt irgendwo, an das Sie eine Referenz zurückgeben; Kunden können dies prüfen; wenn sie nicht überprüfen, erhalten sie vernünftiges Standardverhalten
  • gibt einen Zeiger und keine Referenz zurück; Clients müssten immer den Rückgabewert der Funktion
  • überprüfen
  • eine Ausnahme auslösen; Wenn SomeCondition etwas Außergewöhnliches ist, mit dem Kunden nicht umgehen können, wäre das angemessen
  • behaupten; Wenn SomeCondition immer halten sollte, sollte
  • aktiviert werden
sbi 18.11.2009, 11:29
quelle
13

Ich würde in diesem Fall einen Zeiger anstelle einer Referenz verwenden. Tatsächlich ist dieses Kriterium (optionaler oder obligatorischer Rückgabewert), wie ich mich in erster Linie zwischen Zeigern und Referenzen entscheide.

    
Adrian Grigore 18.11.2009 10:28
quelle
6

Ich würde das wahrscheinlich tun:

%Vor%

Und vielleicht auch:

%Vor%

Anrufer haben dann einige Optionen:

%Vor%

Sie gestalten die Schnittstelle einer Funktion anders, je nachdem, was die Vorbedingungen sind, d. h. wessen Verantwortung es ist, sicherzustellen, dass sie ihre Aufgabe erfüllen kann.

Wenn der Anrufer dafür verantwortlich ist, müssen sie dafür sorgen. Vielleicht möchten Sie es trotzdem überprüfen, nur um auf der sicheren Seite zu sein. Eine Exception zu werfen, wenn die sogenannten "Vorbedingungen" nicht erfüllt werden, macht sie eher zu einem Rat als zu Bedingungen, und es kann ziemlich gut funktionieren, vorausgesetzt, dass Sie den Laufzeit-Overhead von Überprüfungen nicht stören. Ich bin normalerweise ziemlich unversöhnlich mit Vorbedingungen, also könnte ich tatsächlich die bedingte Ausnahme durch eine Bestätigung ersetzen und dokumentieren, dass die Funktion nicht im falschen Modus aufgerufen werden darf. Es hängt davon ab, wie viel Kontrolle der Anrufer über den Modus hat - offensichtlich, wenn er sich willkürlich ändert (zB wenn "SomeCondition" ist "es ist kein Byte auf dem UART verfügbar"), dann brauchen Sie eine ganz andere Schnittstelle als wenn sie sich nur ändert wenn der Client-Code eine Funktion zum Ändern aufruft.

Wenn der Anrufer nicht dafür verantwortlich ist, dass der Modus richtig ist, sollte Ihre Schnittstelle keine Schecks schreiben, die Ihre Implementierung nicht auszahlen kann. Wenn es in diesem Fall "erwartet" wird, dass kein Objekt zurückgegeben wird, sollte die Rückgabe nicht durch Referenz erfolgen. Es sei denn, entweder (a) können Sie ein spezielles "Tut mir leid, es hat nicht funktionieren" -Objekt rascheln, auf das der Anrufer nachsehen kann, oder (b) es ist bequem, Ausnahmen in "erwarteten" Situationen zu werfen. IMO (b) ist in C ++ selten. (a) ist normalerweise nicht besser als einen Nullzeiger zurückgeben, aber gelegentlich ist es. Wenn Sie zum Beispiel eine leere Sammlung zurückgeben, um zu bedeuten, "es gibt nichts, was Sie hier sehen dürfen", könnte dies zu einem sehr sauberen Anrufcode führen, wenn DoSomethingElse() "nichts tun" wäre. Neben den gewünschten Verantwortlichkeiten hängt die Schnittstelle von den erwarteten Anwendungsfällen ab.

    
Steve Jessop 18.11.2009 15:07
quelle
5

Wenn Sie den Rückgabetyp nicht zu einem Zeiger ändern wollten, könnten Sie möglicherweise das Null-Objektmuster verwenden

    
Yacoby 18.11.2009 10:25
quelle
5

Was ist die Lebensdauer von 'ourObject' und wo wird es erstellt?

Wenn Sie vorzeitig zurückkehren müssen, ohne unserObject zu berühren / aktualisieren, und es an dem Punkt existiert, an dem Sie zurückkehren, sehe ich kein Problem mit der Rückgabe eines Verweises darauf.

Wenn Sie mitteilen möchten, dass ein Fehler aufgetreten ist, müssen Sie wahrscheinlich eine Ausnahme auslösen, anstatt vorzeitig zurückzukommen, da der Vertrag, dem Ihre Funktion zugestimmt hat, einen Verweis auf "SomeObject" zurückgibt / p>

Wenn Sie einen Verweis auf ein temporäres Objekt zurückgeben, beheben Sie besser das Problem ...

    
Timo Geusch 18.11.2009 10:26
quelle
5

Ich würde einen booleschen Wert zurückgeben und die Objektreferenz als Parameter an die Funktion übergeben:

%Vor%

In diesem Fall wurde Ihr Objekt nur gefüllt, wenn die Funktion wahr zurückgibt.

    
Patrice Bernassola 18.11.2009 11:18
quelle
3

Äh ... werfen Sie einfach eine Ausnahme ...

    
Tyson 18.11.2009 10:27
quelle
3

Eine Ausnahme auslösen

    
denisenkom 18.11.2009 10:28
quelle
1

Ich werde in Betracht ziehen, nur als Referenz zurückzukommen, wenn ich sicher bin, dass die Funktion niemals fehlschlägt (wahrscheinlich so, als würde man eine const-Referenz auf eine interne Membervariable zurückgeben). Wenn es innerhalb der Funktion mehrere Validierungen gibt, werde ich eine der folgenden Optionen berücksichtigen:

  • Wenn das Objekt nicht kopiert wird teuer, eine Kopie zurückgeben
  • Wenn das Kopieren kostspielig ist, geben Sie a zurück Konst-Zeiger. Zurückgeben von NULL im Fall von Fehler.
Naveen 18.11.2009 10:55
quelle
1

Wenn Sie keine Ausnahme auslösen möchten, können Sie Folgendes versuchen:

%Vor%

Dies bedeutet, dass Sie keine statische Variable irgendwo herumliegen haben müssen, um zurückzukehren, und Sie können es immer noch ohne Parameter nennen. Ich nehme an, Sie würden davon ausgehen, dass der SodeObject () - Zustand standardmäßig der leere Zustand ist, so dass Sie SomeObject testen können, um zu sehen, ob es im leeren Zustand ist. Manchmal ist es auch nützlich, dies zu verwenden, um den Standard-Rückgabewert zu überschreiben, z. GetSomeObject (SomeObject ("Ich bin leer"))

    
AshleysBrain 18.11.2009 11:52
quelle
1

Genau drei Möglichkeiten ...

1. Eine Ausnahme auslösen
2. Gibt ein Dummy-Fehlerobjekt
3. Verwenden Sie einen Zeiger und geben Sie NULL

zurück     
DigitalRoss 19.11.2009 03:15
quelle
0

Ich glaube, die Antwort hängt davon ab, ob Sie die Art von Programmierer sind, der Ausnahmen für schlecht hält und sie nie benutzen will oder nicht. Wenn Sie sie verwenden, und dies ist wirklich eine Ausnahmebedingung, dann muss eine Ausnahme ausgelöst werden. Ja, die Benutzer müssen sich damit auseinandersetzen, aber einen Fehler zu verstecken, um vorzutäuschen, dass nichts passiert ist, ist einfach keine Option. Wenn Sie jedoch keine Ausnahmen verwenden, geben Sie einfach einen Zeiger oder einen booleschen Wert zurück und fügen Sie Ihrer Funktion einen nichtkonstanten Verweis auf SomeObject hinzu. Beide Lösungen sind einfach, aber wer sagt, dass das Überkomprimieren von Code den Code verbessert?

    
user213741 18.11.2009 12:52
quelle
0

Wie die Funktion eingerichtet wird, müssen Sie eine SomeObject zurückgeben oder eine Ausnahme auslösen. Wenn Sie etwas anderes machen wollen, müssen Sie die Funktion ändern. Es gibt keine anderen Möglichkeiten.

Wenn SomeCondition niemals falsch ist, dann können Sie den Test im Code entfernen und stattdessen ein assert eingeben, oder Sie können den Test behalten und eine Ausnahme auslösen. (Ich kann es nicht empfehlen, die Möglichkeit zu vernachlässigen, denn "nie falsch" bedeutet fast immer "niemals falsch, es sei denn, es ist etwas Schlimmes passiert und wurde nicht entdeckt"). p>

Es gibt die Möglichkeit, eine Art Nullobjekt zurückzugeben. Zeiger sind dafür nützlich, da es einen offensichtlichen Nullwert gibt, der falsch testet, aber Sie könnten ein Flag als out-Parameter zurückgeben oder ein spezielles Objekt zurückgeben, das als Null definiert ist. Dann müssen Sie den Rückgabewert bei jedem Aufruf testen, damit dies sinnvoll ist, und das ist wahrscheinlich nicht weniger aufwändig als die assert oder throw .

Wenn ich das täte, würde das von SomeCondition abhängen. Wenn es Nebenwirkungen hat oder schwer zu berechnen ist, testen und werfen Sie eine Ausnahme, wenn sie falsch ist. Wenn es schwer ist zu berechnen, verwenden Sie assert , so dass Sie es in der Produktion nicht tun müssen und darüber hinaus vergessen.

    
David Thornley 18.11.2009 15:45
quelle
0

Dies ist die gleiche Situation wie der integrierte C ++ Operator dynamic_cast<> . Es kann entweder in einen Zeigertyp oder einen Referenztyp umgewandelt werden. Wenn es sich um einen Zeigertyp handelt, wird bei einem Fehler NULL zurückgegeben. Wenn es sich um einen Referenztyp handelt, wird bei einem Fehler die Ausnahme std::bad_cast ausgelöst. Nach dem gleichen Beispiel würden Sie eine Ausnahme auslösen.

    
newacct 15.11.2011 20:38
quelle

Tags und Links