ist eine Referenz als Rückgabewert immer schlecht?



  • Hallo Leute.

    Ich möchte gerne folgendes machen:

    // irgendwo in 'meineKlasse':
    private:
    	std::map <int, Datentyp> m_meineMap;
    
    Datentyp &meineKlasse::getDatentypFromMap(int key)
    {
    	if (m_meineMap.find(key) != m_meineMap.end())
    	{
    		return m_meineMap.at(key);
    	}
    	else
    	{
    		m_meineMap[key];
    		return m_meineMap.at(key);
    	}
    }
    

    Ich möchte also eine Membervariable als Referenz zurückgeben (nur Objektintern). In diesem Falle ist es ein Wert aus einer Map. Der Anwendungsfall ist zeitkritisch und daher möchte ich gerne unnötiges kopieren bestehender Daten vermeiden. Nun lese ich immer wieder in englisch-sprachigen Foren, wie schlimm es doch sei, eine Referenz als Rückgabewert zu nutzen. ...gut, wenn ich was im Stack alloziere und als Ref zurückgebe, ist es nicht so prickelnd. Aber Membervariablen sollten doch ok sein, oder? Bis jetzt habe ich noch nie Referenzen als Rückgabewert genutzt.

    viele Grüße,
    SBond



  • Du weißt aber schon, dass der gesamte Code deiner Funktion getDatentypFromMap auf

    return m_meineMap[key];
    

    eingedampft werden könnte?

    Und beachte, dass die Referenz, die du zurückgibst, ungültig wird, sobald jemand in die Map ändert (also nicht die Werte, aber z.B. wenn jemand nen Key einfügt). Ich sehe erstmal nicht, warum ich meineMap[k] in eine Funktion packen sollte.



  • wob schrieb:

    Und beachte, dass die Referenz, die du zurückgibst, ungültig wird, sobald jemand in die Map ändert (also nicht die Werte, aber z.B. wenn jemand nen Key einfügt).

    Das ist falsch.



  • wob schrieb:

    Du weißt aber schon, dass der gesamte Code deiner Funktion getDatentypFromMap auf

    return m_meineMap[key];
    

    eingedampft werden könnte?

    ähh.. ja.
    ...ja das ist hier ein häufiges Problem von mir den Code hier soweit zu reduzieren, dass man nicht mehr den Sinn erkennt. Und in diesem Falle hättest du recht.

    eventuell ist es so besser:

    Datentyp &meineKlasse::getDatentypFromMap(int key)
    {
        if (m_meineMap.find(key) == m_meineMap.end())
        {
            m_meineMap[key];
        }
    
    	// ...ggf. Prüfungen/Anpassungen von m_meineMap.at(key) an dieser Stelle...
    
    	return m_meineMap.at(key);
    }
    

    Exisiert ein Wert nicht, so wird er angelegt. Danach erfolgen noch einige Prüfungen und ggf. Anpassungen (initialisierungen oder ähnliches). Zum Schluss wird die Ref zurückgegeben.

    Während mit der Referenz gearbeitet wird, ändert sich an der Map gar nichts. Somit dürfte es doch ok sein, oder?


  • Mod

    SBond schrieb:

    eventuell ist es so besser:

    Datentyp &meineKlasse::getDatentypFromMap(int key)
    {
        if (m_meineMap.find(key) == m_meineMap.end())
        {
            m_meineMap[key];
        }
    	
    	// ...ggf. Prüfungen/Anpassungen von m_meineMap.at(key) an dieser Stelle...
    	
    	return m_meineMap.at(key);
    }
    

    Exisiert ein Wert nicht, so wird er angelegt.

    äh, nein. Der find-Test ist in jedem Fall überflüssig.
    Das Mischen von [] und at in der gleichen Funktion stellt ist praktisch immer Unfug. Entweder man beabsichtigt, ggf. Default-Elemente einzufügen oder das Nichtvorhandensein anders zu handhaben. Und wenn das Element einmal ermittelt wurde, gibt es keinen Grund, [] oder at nochmals aufzurufen, das ist schließlich keine O(1)-Operation.

    Datentyp &meineKlasse::getDatentypFromMap(int key)
    {
        Datentyp& my_element = m_meineMap[key];
    
        // ...ggf. Prüfungen/Anpassungen von my_element an dieser Stelle...
    
        return my_element;
    }
    


  • manni66 schrieb:

    wob schrieb:

    Und beachte, dass die Referenz, die du zurückgibst, ungültig wird, sobald jemand in die Map ändert (also nicht die Werte, aber z.B. wenn jemand nen Key einfügt).

    Das ist falsch.

    Ups, hast recht, wieder was gelernt. Habe bislang immer so programmiert, als sei es nicht so.
    http://www.cplusplus.com/reference/map/map/operator[]/ sagt: Iterator validity No changes.

    Ich dachte immer, das sei so ähnlich wie beim vector, dass irgendwann ein resize nötig werden kann, sodass ggf. umkopiert werden muss. Bzw. dass bei der Map irgendwann der Baum umgeordnet wird und somit die Referenzen anders werden. Es scheint aber eine Indirektion mehr eingebaut zu sein. Ergo: nicht denken, sondern immer in der Doku nachgucken.

    Naja, jedenfalls hat camper richtige Anmerkungen gemacht, dann am Ende dann aber doch wieder .at() beim return benutzt, wo es nicht nötig gewesen wäre.


Anmelden zum Antworten