Rückgabewert für "Keine Lösung"



  • Frager schrieb:

    @JaykopX Danke, meine Frage war an fr33g gerichtet. Du hast ja klar gesagt, welche du vorziehst.

    ja ich würde die nullstelle dann als referenz zurückgeben.
    so wies ja glaub ich in deinem vorschlag auch ist.
    du hast in deiner main funktion eine variable int nullstelle.
    so und das ergebnis deiner funktion teilst du dann der nullstelle zu.
    da die als referenz übergeben wird, hast du ja damit die nullstelle in deiner main funktion;-)



  • Frager schrieb:

    @volkard: Für Nullstellen wohl die beste Lösung, aber das sollte nur ein Beispiel für eine Funktion sein, die einen "speziellen" Rückgabewert für "keine Lösung" (aber nicht "Fehler") braucht.

    Allgemein läßt sich keine Aussage machen.
    Nehmen wir kleine Objekte, geht meistens pair<bool,Object>, werden sie größer, mut vielleicht bool foo(Object&) sein, Aber was ist, wenn es keine ungültigen Objekte geben kann, dann geht nur Zeiger, aber und und und. Ganz zu vergessen von Überladung mit ungültigen Werten, wie INVALID_HANDLE_VALUE, geschloseenen fstreams, 0 als Zeiger, -1 als Array-Index und so.



  • Ich finde die bool -Rückgabe gut. Die Anwendung ist recht einfach:

    int ns;
    if (nullstelle(gerade, ns))
    {
        // ...
    }
    

    Beim Paar ist es zwar nicht viel komplizierter, ich mag es allerdings, wenn man den Rückgabewert direkt nutzen kann und nicht erst zerlegen muss.

    std::pair<bool, int> pair = nullstelle(gerade);
    if (pair.first)
    {
        // ...
    }
    

    Eine Exception würde ich nicht verwenden und auf INT_MAX abzufragen finde ich auch nicht besonders sinnvoll.



  • Was spricht denn nun dagegen, Nullstellen in einer Liste (oder vergleichbares) zurueckzugeben? Eine leere Liste zeigt an, dass kein Nullstellen existieren. Da sie sowieso weiterverarbeitet werden sollen (z.B. alle NST ausgeben) kann sich die Abfrage des Rueckgabewertes gespart werden und gleich mittels for oder for_each ueber die Liste iteriert werden.

    typedef std::list<double> Zeros // oder complex oder float oder ...
    
    Zeroes nullstellen()
    // oder ...
    void nullstellen(Zeroes& zs)
    


  • Was spricht denn nun dagegen, Nullstellen in einer Liste (oder vergleichbares) zurueckzugeben?

    Nichts. (nur sind die Nullstellen wie gesagt nur ein Beispiel)
    Würdest du auch einen Container verwenden, wenn maximal 1 Element zurückgegeben wird?



  • Frager schrieb:

    Würdest du auch einen Container verwenden, wenn maximal 1 Element zurückgegeben wird?

    Wäre mir mit Standard-Containern zu teuer.
    Aber ich muß es mal testen. Einen Container für 0 oder 1 Element habe ich noch rumliegen.



  • Frager schrieb:

    Was spricht denn nun dagegen, Nullstellen in einer Liste (oder vergleichbares) zurueckzugeben?

    Nichts. (nur sind die Nullstellen wie gesagt nur ein Beispiel)
    Würdest du auch einen Container verwenden, wenn maximal 1 Element zurückgegeben wird?

    In Haskell wird es so gemacht. Zwar gibt es Maybe, aber meist greift man doch auf [] bzw. [a] zurueck.

    Aber ich muß es mal testen. Einen Container für 0 oder 1 Element habe ich noch rumliegen.

    Naja, es gibt auch Maybe fuer C++, aber da haengt dann aber noch der ganze Monadkram dran.



  • [quote=volkard]Einen Container für 0 oder 1 Element habe ich noch rumliegen.[/quote]
    Was ist mit boost::optional?



  • Frager schrieb:

    Was ist mit boost::optional?

    Das ist genau für solche Fälle gemacht 🙂



  • Ja, scheint so, als ob optional<T> die boost-Antwort auf Maybe bzw. [a] und [] ist. Leider spare ich mir trotzdem nicht die if-Abfrage.



  • knivil schrieb:

    Leider spare ich mir trotzdem nicht die if-Abfrage.

    Kann man sich die überhaupt sparen? Denn es muss ja ein anderer Ablaufpfad eingeschlagen werden, abhängig davon, ob die Funktion Nullstellen hat oder nicht. (Ich möchte jetzt nicht auf If-Workarounds wie Funktionszeiger oder sowas hinaus).



  • Ok, das scheint mir für viele Fälle die "schönste" Lösung zu sein. Danke für die Antworten.



  • Nexus schrieb:

    Kann man sich die überhaupt sparen? Denn es muss ja ein anderer Ablaufpfad eingeschlagen werden, abhängig davon, ob die Funktion Nullstellen hat oder nicht. (Ich möchte jetzt nicht auf If-Workarounds wie Funktionszeiger oder sowas hinaus).

    Wenn man z.B. mehrere Rueckgabewerte hat, dann will man diese fuer gewoehlich weiterverarbeiten. Tu was mit allen Nullstelln, Tu was mit allen Matches des regulaeren Ausdrucks, ... Im einfachsten Fall moechte man diese erst mal ausgeben, also for*( it = matches.begin(); it != matches.end(); ++it)* oder mittels std::for_each(...). Ist jetzt der Container aber leer, so passiert gar nichts. Bei der Variante mit expliziten Rueckgabewert, std::pair oder boost::optional muss dieser erst geprueft werden. Diese Pruefung ist natuerl auch in der Variante mit for enthalten, aber sie ist implizit und muss nicht hingeschrieben werden. Und bei allem, was ich nicht dasteht, kann ich auch keine Fehler machen. Der Code hat etwas weniger Rauschen (Laerm, noise). Performanceunterschiede wird es wohl nicht geben.



  • pumuckl schrieb:

    Frager schrieb:

    Was ist mit boost::optional?

    Das ist genau für solche Fälle gemacht 🙂

    Mag sein, aber es ist verboostelt und damit für mich indiskutabel.
    Außerdem wollte ich einen CONTAINER, also mit begin() und end() bzw mit content().



  • volkard schrieb:

    Mag sein, aber es ist verboostelt und damit für mich indiskutabel.

    Klingt nach ner emotionalen Entscheidung, die imo nichts bei der Wahl der Mittel für sowas zu suchen hat. Es sei denn "verboostelt" heißt sowas wie "zu allgemein und daher mit performance-overhead".

    volkard schrieb:

    Außerdem wollte ich einen CONTAINER, also mit begin() und end() bzw mit content().

    Der OP wollte aber keinen Container sondern nur eine Möglichkeit, zusätzlich zur Menge der möglichen einzelnen Lösungen den Wert "keine Lösung" auszudrücken. Von begin(), end() etc. war nie wirklich die Rede.



  • pumuckl schrieb:

    volkard schrieb:

    Mag sein, aber es ist verboostelt und damit für mich indiskutabel.

    Klingt nach ner emotionalen Entscheidung, die imo nichts bei der Wahl der Mittel für sowas zu suchen hat. Es sei denn "verboostelt" heißt sowas wie "zu allgemein und daher mit performance-overhead".

    volkard schrieb:

    Außerdem wollte ich einen CONTAINER, also mit begin() und end() bzw mit content().

    Der OP wollte aber keinen Container sondern nur eine Möglichkeit, zusätzlich zur Menge der möglichen einzelnen Lösungen den Wert "keine Lösung" auszudrücken. Von begin(), end() etc. war nie wirklich die Rede.

    volkard schrieb:

    Frager schrieb:

    Würdest du auch einen Container verwenden, wenn maximal 1 Element zurückgegeben wird?

    Wäre mir mit Standard-Containern zu teuer.
    Aber ich muß es mal testen. Einen Container für 0 oder 1 Element habe ich noch rumliegen.

    Frager schrieb:

    volkard schrieb:

    Einen Container für 0 oder 1 Element habe ich noch rumliegen.

    Was ist mit boost::optional?

    pumuckl schrieb:

    Frager schrieb:

    Was ist mit boost::optional?

    Das ist genau für solche Fälle gemacht 🙂

    Klingt danach, als sei boost genau für solche Fälle gemacht, wo man einen kleinen Container haben will.



  • volkard schrieb:

    Klingt danach, als sei boost genau für solche Fälle gemacht, wo man einen kleinen Container haben will.

    Du hast den Container aufgebracht mit dem Argument dass später irgendwann mal eh mehrere Ergebnisse zurückgegeben werden müssten.
    boost::optional ist eben kein wirklicher container (was du ja bemängelt hast, weils kein begin() und end() dabei ist), sondern eine Lösung für die Situationen wo ein Container overkill wäre.



  • Ich trage nach, daß darüberhinaus ein Container recht sinnig ist, weil er auf natürliche Weise ausdrückt, daß es keine oder eine Lösung gibt. So, wie man im Schulunterricht immer eine Lösungsmenge, die gegebenenfalls leer ist, als Ergebnis hinschreiben soll.



  • Einen echten Container ala vector zu verwenden wäre in diesem Fall (Schnittpunkt zweier Geraden ermitteln) eine schwere Performance-Sünde.

    boost::optional ist etwas besser.

    std::pair<bool, int> bzw. die Variante die das Ergebnis per Output-Parameter zurückgibt sind vermutlich für diesen speziellen Fall die "besten" Lösungen.



  • Nicht vergessen, dass es auch unendlich viele Nullstellen geben kann 🙂


Anmelden zum Antworten