Zeiger einer erfolglosen Suche zurückgeben



  • Hi,

    ein prob über das ich immer wieder stolpere :

    Ich möchte einen Zeiger von einer Suche zurückbekommen

    Sample->GetByText("Test")->Machiwas()

    wenn die Suche aber erfolglos ist, müsste ich einen NULL-Zeiger zurückgeben, was aber in einer Exzeption endet.

    Wie löse ich das am besten?



  • Mh, ein Weg wäre folgender:

    Status Quo:

    class Foo
    {
    public:
    	void machIrgendwas();
    };
    
    class Sample
    {
    public:
    	Foo* getByText(std::string const& name)
    	{
    		assert(contains(nameToFoosMap, name));
    		return &nameToFoosMap[name];
    	}
    };
    
    // später:
    Sample s = ...;
    s->getByText("test")->machIrgendwas();
    
    class FooInterface
    {
    public
    	virtual void machIrgendwas() = 0;
    };
    
    class DefaultFoo : public FooInterface
    {
    public:
    	void machIrgendwas()
    	{}
    };
    
    class Foo : public FooInterface
    {
    public:
    	void machIrgendwas()
    	{
    		//...
    	}
    };
    
    class Sample
    {
    	static DefaultFoo defaultValue;
    
    public:
    	Foo* getByText(std::string const& name)
    	{
    		auto it = nameToFoosMap.find(name);
    		if ( it != std::end(nameToFoosMap) )
    			return &it->second;
    
    		return &defaultValue;
    	}
    };
    
    // später:
    Sample s = ...;
    s->getByText("test")->machIrgendwas();
    

    Die Idee ist im Grunde: wenn der Wert da ist, gib ihn zurück. Wenn nicht, gib Stellvertretend ein ein leeres Objekt zurück, was nix macht.



  • Oder noch viel besser weil eindeutiger:

    Sample* foundSample = mySample->GetByText("Test");
    
    if (foundSample) {
        foundSample->MachWas();
    }
    


  • @sampler: sry, hätte das dazuschreiben sollen, genauso hatte ich es bisher gemacht 😉

    @sky...: genau was ich gesucht habe! THX

    [Edit]

    Mh, ein Weg wäre folgender:

    gerade noch gelesen, fallen dir noch andere Wege ein(net genug bekomm^^)



  • @sampler: sry, hätte das dazuschreiben sollen, genauso hatte ich es bisher gemacht 😉

    und so war und ist es richtig

    für die Do-Nothing-Objekt-Sache wird dir von den meisten Entwicklern und Firmen der Kopf abgeschraubt - es macht Fehlerfindung sehr schwer und vermittelt das Bild als wäre es per se Execption/Error-Safe - was es aber nicht ist

    also mach es richtig mit dem if - oder warte darauf das einer mit dem Kopfabschrauber kommt



  • mcam77 schrieb:

    @sampler: sry, hätte das dazuschreiben sollen, genauso hatte ich es bisher gemacht 😉

    und was stört dich daran?



  • ok, lass mich ja gerne belehren!

    mich würde zwar der Unterschied noch prinzipiell interessieren, aber wir müssen das net bis ins kleinste ausdiskutieren.

    lg



  • Warum nicht boost::optional verwenden ?



  • case schrieb:

    Warum nicht boost::optional verwenden ?

    Weil es ihm nix bringt? Braucht er ja erst wieder ein if überall. Kann er gleich weiterhin NULL als "special value" verwenden.

    mcam77 schrieb:

    mich würde zwar der Unterschied noch prinzipiell interessieren, aber wir müssen das net bis ins kleinste ausdiskutieren.

    Der Unterschied zwischen was und was?
    Zwischen "mit if überall" und der Version von Skym0sh0?
    Steht doch alles an Code da, der Unterschied ist ... naja, du musst ja nur den Code lesen. Was genau bereitet dir dabei Probleme?



  • Hi hustbaer,

    du hasts genau erfasst, die version von sky sieht für mich halt besser aus, bedeutet aber das ich mir selber den kopf abschrauben muss^^

    Wenn ich ein Default-Objekt kreiere, müsste ich ja auch wieder abfragen ob das Objekt z.B. "" oder 0 ist und kann eig. gleich wieder auf NULL prüfen.

    Der Unterschied bezog sich also darauf: Auf NULL prüfen oder ein Default-Objekt ("" oder 0) erstellen und das zu prüfen, und ob ich mir da dann selber auch den Kopf runterschrauben muss ^^

    Ich hatte halt iwie die Hoffnung das ich mir diese NULL-Abfragen sparen kann.

    Aber wenn wirs jetzt schon ausdiskutieren:

    Kann ich bei unkritischen Sachen die Lösung von sky nutzen? Also das z.B. im schlimmsten Fall dann in einer Listbox ein leerer String auftaucht.

    Viel. ergibts sichs ja mal das ich mir zig abfragen auf NULL sparen kann. 🙂

    lg



  • mcam77 schrieb:

    Wenn ich ein Default-Objekt kreiere, müsste ich ja auch wieder abfragen ob das Objekt z.B. "" oder 0 ist und kann eig. gleich wieder auf NULL prüfen.

    Warum? Musst du nicht, du rufst einfach etwas auf.
    Ich weiß nicht, obs bei dem konkreten Beispiel jetzt Sinn macht. Grundsätzlich kann ich mir aber schon Fälle vorstellen, wo ein Standardobjekt, das einfach etwas bzw. nichts macht, "besser" wäre als ständige Prüfungen auf null. z.B. weils besser lesbar wäre, Sonderfälle versteckt oder sowas. Das kommt ziemlich häufig vor, gibt sogar ein Design Pattern dafür, "null object pattern".



  • Es gibt sicherlich Fälle wo so ein "mach einfach nix" Objekt OK ist.
    Je schmaler das Interface so eines Objekts, je genauer seine Rolle in einem Bestimmten Programm oder Programmabschnitt definiert ist, desto eher.

    Also beispielsweise wenn man einen Programmabschnitt der irgendwelche Daten produziert, und diese an ein Sink-Interface schickt. Nehmen wie an dieser Programmabschnitt macht davon abgesehen aber auch noch was sinnvolles, so dass es in bestimmten Fällen erwünscht sein könnte die Daten einfach zu verwerfen. Dann kann man natürlich eine NullSink Klasse bauen, und diese verwenden. Anstatt alles mit if (sink != nullptr) vollzusauen.

    (Ein konkretes Beispiel wäre ein Programm das bestimmte Daten dekodiert, vielleicht Audiofiles. Wenn man nur prüfen will ob das File OK ist, dann braucht man die dekodierten Audiodaten eigentlich nicht -- der Prozess des Dekodierens alleine ist ausreichend um eventuelle Formatfehler zu finden. Man kann die Daten also einfach verwerden.)

    Allerdings gibt es genau so Fälle wo es nicht oder nur schwer möglich ist so ein "mach einfach nix" Objekt zu bauen. z.B. schonmal wenn mit konkreten Klassen statt Interfaces gearbeitet wird. Wenn man den Code ändern kann, kann man natürlich ein Interface einziehen. Und je nachdem wie schmal & spezifisch das dann ist, kann das schon reichen damit man wieder sein "mach einfach nix" Objekt verwenden kann.

    Allgemein würde ich sagen: wenn man für das "mach einfach nix" Objekt keine eigene Klasse definiert, die dann auch wirklich nix macht (bzw.: genau das macht was man in der spezifischen Situation braucht), dann sollte man die Sache zumindest gut dokumentieren. Also wenn man z.B. irgendwo ne unsichtbare Textbox macht, bloss weil ein Programmabschnitt halt ne Textbox erwartet wo er reinschreiben kann... Sowas fände ich ohne Kommentar reichlich verwirrend.



  • hustbaer schrieb:

    Kann er gleich weiterhin NULL als "special value" verwenden.

    oder besser nullptr 😉



  • Ja. Hab' im 2. Beitrag eh brav nullptr geschrieben.



  • @hustbaer: du bist um kurz vor 4 noch auf und kurz nach 10 schon wieder auf, oder wieder noch, oder brauchst du keinen Schlaf?



  • War zwischen 2 und 4 heia, konnte net ordentlich schlafen, musste aber früh raus. Schlaf brauch ich schon. Leider. 🕶



  • machIrgendwas(s->getByText("test")->);
    

Log in to reply