tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
11
ZUGRIFFE
247
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Cyraid Cyraid ist offline Mitglied Silber
    Registriert seit
    May 2006
    Beiträge
    55
    Hallo

    Hat man eine selbstdefinierte Klasse A und man möchte eine Funktion schreiben, die ein Objekt dieser Klasse zurückgibt, wie geht man am Besten vor?

    Ich habe drei Alternativen im Angebot:
    Code :
    1
    2
    3
    4
    5
    
    A* methodeXY() {
      // Berechnungen
      A* a = new A(...);
     return a;
    }
    Wobei ich mir hier unsicher bin, ob der so erstellte Zeiger auf das Objekt vom Typ A innerhalb der Methode nach dem Methodenauffruf nicht ungültig wird ?

    Code :
    1
    2
    3
    4
    
    A methodeXY() {
      // Berechnungen
      A* a = new A(...);
      return *a;
    Hier wird eine Kopie erstellt, was die Laufzeit drückt.

    Code :
    1
    2
    3
    4
    
    void methodeXY(A* a) {
      // Berechnungen
      a = new A(...);
    }
    Auch hier die Frage, ob der Zeiger nach dem Methodenaufruf noch gültig ist?

    Welche Variante ist die eleganteste ? Welche sollte man vorziehen und welche meiden ?

    Danke und schöne Grüße, Cyraid

    EDIT: Syntaktische Fehler ausgebessert.
    Geändert von Cyraid (15.05.10 um 15:16 Uhr)
     

  2. #2
    badday badday ist offline Mitglied Brokat
    Registriert seit
    Dec 2009
    Beiträge
    321
    Blog-Einträge
    1
    Wenn du das Objekt selbst zurückgeben willst, warum benutzt du nicht einfach
    return *this;
    ?

    Gruß,

    badday
     

  3. #3
    Cyraid Cyraid ist offline Mitglied Silber
    Registriert seit
    May 2006
    Beiträge
    55
    Zitat Zitat von badday Beitrag anzeigen
    Wenn du das Objekt selbst zurückgeben willst, warum benutzt du nicht einfach
    return *this;
    ?
    Die Methode XY ist nicht notwendig eine Methode der Klasse A. Sie könnte z.B. auch global sein.
     

  4. #4
    Cromon Cromon ist offline Mitglied Brillant
    Registriert seit
    Apr 2008
    Beiträge
    819
    Hallo Cyraid!

    Deine zweite Variante ist syntaktisch nicht korrekt, denn new liefert dir einen Zeiger zurück und kann daher nicht direkt nach A umgewandelt werden.

    Deine dritte Variante funktioniert nicht, denn du musst bedenken, dass es sich bei deinem Funktionsargument nur um eine Variable mit dem gleichen Inhalt handelt wie du sie später aufrufst. Daher hat eine Wertzuweisung an dieses lokale Objekt keinen Einfluss auf das Objekt, mit dem du die Funktion aufrufst.

    Der Speicher, den du mit new allozierst ist bekanntermassen persistent bis zu einem Aufruf an delete oder dem Programmende.

    Für deine dritte Variante gäbe es die Möglichkeit folgendes zu verwenden:
    Code :
    1
    2
    3
    4
    5
    6
    
    void CreateInstance(A** ppDest)
    {
             if(ppDest == NULL)
                    // errorhandling (exception werfen, ...)
             *ppDest = new A;
    }

    Ich finde das allerdings problematisch, da man blind davon ausgeht, dass das worauf ppDest zeigt ein korrekter Platz ist.

    /Edit:
    Meine Nummerierungen decken sich leider nicht mit deinen Codesnippets, aber es sollte dennoch klar sein, was gemeint ist
    Geändert von Cromon (15.05.10 um 15:18 Uhr)
     

  5. #5
    badday badday ist offline Mitglied Brokat
    Registriert seit
    Dec 2009
    Beiträge
    321
    Blog-Einträge
    1
    Ich würde hier einfach einen Smart-Pointer mit Verwendungszähler verwenden.
    Wenn du im 1. Versuch das Objekt völlig neu erstellst, kann du das ihne Probleme so machen (soweit ich das sehe), allerdings musst du halt später delete aufrufen.

    Gruß,

    badday
     

  6. #6
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Bei Code 3, das "*A a" soll wohl "A *a" heißen?

    Bei Variante 1 bleibt der Pointer gültig, ist soweit ok.
    Bei Variante 3 reservierst du Speicher, auf den du nie wieder zugreifen kannst und verstopfst damit nur den Speicher; also weg damit.

    Bei Allokierungen in Methoden vergisst man aber leicht aufs freigeben danach.
    Besser da freigeben, wo es auch reserviert wird.
     

  7. #7
    Cyraid Cyraid ist offline Mitglied Silber
    Registriert seit
    May 2006
    Beiträge
    55
    @Cromon: Danke für deine ausführliche Antwort.

    Entschuldigung, da haben sich beim schnellen Abtippen ein paar syntaktische Fehler eingeschlichen. Habe sie korrigiert.

    Die ausgebesserte 2.Variante wäre also eine gute Art der Realisierung trotz des Kopierens ?

    Zitat Zitat von Cromon Beitrag anzeigen
    Der Speicher, den du mit new allozierst ist bekanntermassen persistent bis zu einem Aufruf an delete oder dem Programmende.
    Stimmt, danke für den Hinweis. Das bedeutet demnach, dass die 1. Variante problemlos funktionieren würde. Gibt es für 1. Variante Nachteile? Ist das ein guter Stil?


    Schöne Grüße, Cyraid
     

  8. #8
    Cromon Cromon ist offline Mitglied Brillant
    Registriert seit
    Apr 2008
    Beiträge
    819
    Nein, die zweite Variante ist sehr schlecht. Der Speicher, den du da allozierst mit new kannst du nie mehr freigeben, da du die Adresse nicht zurückgibst.

    Zum Thema kopieren:
    Praktisch alle Optimierer optimieren solche Sachen, dass das dennoch über Zeigerrückgabe realisiert wird und der Kopiervorgang unterdrückt wird. Schau dir dazu einfach mal den Assemblercode an, den dein Compiler generiert (am besten zur Laufzeit via Debugger und einem Breakpoint).
     

  9. #9
    Cyraid Cyraid ist offline Mitglied Silber
    Registriert seit
    May 2006
    Beiträge
    55
    Zitat Zitat von Cromon Beitrag anzeigen
    Nein, die zweite Variante ist sehr schlecht. Der Speicher, den du da allozierst mit new kannst du nie mehr freigeben, da du die Adresse nicht zurückgibst.
    Stimmt.

    Zitat Zitat von Cromon Beitrag anzeigen
    Zum Thema kopieren:
    Praktisch alle Optimierer optimieren solche Sachen, dass das dennoch über Zeigerrückgabe realisiert wird und der Kopiervorgang unterdrückt wird. Schau dir dazu einfach mal den Assemblercode an, den dein Compiler generiert (am besten zur Laufzeit via Debugger und einem Breakpoint).
    Danke für die Informationen. Demnach ist also eine Variante mit Kopie in Ordnung? Beispielhaft zwei Versionen:
    Code :
    1
    2
    3
    4
    5
    
    A methodeXY() {
      // Berechnungen
      A a(...);
     return a;
    }

    oder

    Code :
    1
    2
    3
    4
    5
    
    void methodeXY(A* a) {
      // Berechnungen
      A b(...);
      *a = b;
    }

    Gibt es zwischen diesen beiden Nachteile/Vorteile ?

    Schöne Grüße, Cyraid
     

  10. #10
    badday badday ist offline Mitglied Brokat
    Registriert seit
    Dec 2009
    Beiträge
    321
    Blog-Einträge
    1
    Warum benutzt du bei deiner zweiten Methode nicht einfach eine Referenz?

    Gruß,

    badday
     

  11. #11
    Cromon Cromon ist offline Mitglied Brillant
    Registriert seit
    Apr 2008
    Beiträge
    819
    Dass Kopieren generell in Ordnung ist kann man so nicht sagen. Der Optimierer hat auch irgendwo seine Grenzen und fixen Möglichkeiten. Es sollte nur sagen, dass praktisch alles immer mit Bedacht ausgedrückt werden sollte, im Sinne von "sag niemals nie".

    Wenn du unnötige Kopien vermeiden kannst spricht eigentlich nichts dagegen das auch zu tun ausser du weisst zu 100%, dass dein Optimierer sich genau diese Gedanken auch macht und dann deinen Code entsprechend umformt.
     

  12. #12
    OnlyFoo OnlyFoo ist offline Mitglied Brokat
    Registriert seit
    Feb 2005
    Beiträge
    470
    Zitat Zitat von badday Beitrag anzeigen
    Warum benutzt du bei deiner zweiten Methode nicht einfach eine Referenz?

    Gruß,

    badday
    Finde ich je nach Methode auch eine gute Idee.
    Code cpp:
    1
    2
    3
    4
    
    void machWas( A& a ) {
       a.machwas();
       a.machNochWas();
    }

    Dann kannst du machen:
    Code cpp:
    1
    2
    
    A a;
    machWas(a);

    Macht natürlich nur Sinn, wenn "machWas" nicht als Methode von A besser aufgehoben wäre.


    Weniger Sinn macht das natürlich, wenn du ein Objekt erzeugen möchtest. Aber je nach Verwendung würd ich wahlweise einfach das Objekt zurück geben (und hoffen dass der Compiler optimiert) oder einen auto_ptr oder shared_ptr zurück geben. C++0x bringt dann irgendwie Movable-Dinger oder so, womit man so eine Rückgabe ohne kopie machen kann.
     

Ähnliche Themen

  1. Wurf eines Objekts
    Von Cromon im Forum Coders Talk
    Antworten: 9
    Letzter Beitrag: 22.04.10, 19:44
  2. Referenznummer eines Objekts
    Von greggy80 im Forum Javascript & Ajax
    Antworten: 4
    Letzter Beitrag: 16.09.09, 16:31
  3. Nachbelichten eines Ai-Objekts
    Von jassebutter im Forum Vektor-Programme
    Antworten: 7
    Letzter Beitrag: 20.08.09, 14:23
  4. Rekonvertierung eines Objekts möglich?
    Von pixels pix im Forum Cinema 4D
    Antworten: 3
    Letzter Beitrag: 07.06.07, 22:04
  5. Antworten: 0
    Letzter Beitrag: 28.12.04, 16:32