vector oder vector*



  • Hallo ich bin neu mit c++. Ich wäre froh wenn mir jemand den Unterscheid erklärt. Wenn ich einen vector erstelle mit
    vector<char*> v;
    Dann habe ich einen Zeiger auf den Vector?

    Wenn ich nun z.B. die Funktion

    vector<char*> get(){
    return sequences;
    }
    

    schreibe. Wird dann ein Pointer auf den Vector zurück gegeben oder eine kopie des Vectors mit seinem ganzen Inhalt?

    Müsste es eigentlich heißen? (Bringt compile fehler)

    vector<char*> *get(){
    return sequences;
    
    }
    

    Bin dankbar wenn mri jemand ein paar Zeilen dazu schreiben kann, komm als java Mensch nochnicht mit Pointern und Refernezn klar.

    Danke



  • Wenn du
    vector<char*> v;
    schreibst hast du, anders als in Java, direkt ein vector Objekt.

    vector<char*>* v = 0;
    ist ein Zeiger auf einen Vector; hier mit 0 initialisiert (der Zeiger, es gibt noch kein Objekt).

    Wenn du Werte an Funktionen übergibst bzw zurückgibst solltest du
    a) Referenzen
    void Test(vector<char*>& v) {...}
    b) Zeiger
    void Test(vector<char*>* v) {...}
    nehmen. Sonst wird eine komplette Kopie des Objekts erzeugt.
    Bei einfachen Datentypen (int,double,...) tut eine Kopie meist nicht weh.

    Aufruf:
    vector<char*> v;
    a) Referenzen
    Test(v);
    b) Zeiger
    Test(&v); // &v gibt dir die Adresse von v zurück



  • ah danke,

    dann gibt es aber nicht viel unterscheid zwiscehn zeigern und referenzen?

    Außer dass ich bei Referenzen v gleich verwenden kann.

    Wird bei deinem Aufruf a) Test(v) für void Test(vector<char*>& v) {...} automatisch eine Referenz auf v übergeben ohne, dass das bei dem Funktionsaufruf angeben zu müssen?



  • wolf.grad schrieb:

    Wird bei deinem Aufruf a) Test(v) für void Test(vector<char*>& v) {...} automatisch eine Referenz auf v übergeben ohne, dass das bei dem Funktionsaufruf angeben zu müssen?

    Ja

    Referenzen müssen anders als in Java immer auf ein gültiges Objekt verweisen und du kannst eine Referenz nicht an ein anderes Objekt "binden".
    Eigentlich sind Zeiger das was du von Java als Referenz kennst. Eine Referenz ist in C++ ein eher ein alias für ein Objekt.



  • Danke jetzt wirds so langsam klar.

    Also vllt kannst du mir noch nen tipp geben ob ich für meine Aufgabe auf dem richtigen Weg bin.

    Ich will eine Klasse zum ablegen von Daten haben.
    z.B.:

    using namespace std;
    class CStore{
    
    protected:
    vector<char*> m_sequences;
    int m_classnr;
    
    public:
    	CStore(int classnr);
    
    vector<char*>& getSequences();
    
    void addSequenz(char* pos);
    
    };
    
    #include "stdafx.h"
    #include <vector>
    #include "Store.h"
    
    CStore::CStore(int classnr){
    	m_classnr = classnr;
    }
    
    vector<char*>& CStore::getSequences(){
    return m_sequences;
    
    }
    
    void CStore::addSequenz(char* pos){
    ...
    }
    

    Hier ist doch dann solange der CStore existiert jede Referenz auf m_sequences gültig?

    Ich will diese Stores jetzt dynaisch erzeugen mit new CStore(12). Wenn ich damit fertig bin reicht ein einfaches delete? Oder muss ich einen Destructor schreiben indem m_sequences.clear() aufgerufen wird, oder muss ich jedes char-Array auch noch vernichten?

    Schonmal vielen Danke



  • wolf.grad schrieb:

    Hier ist doch dann solange der CStore existiert jede Referenz auf m_sequences gültig?

    Ja

    wolf.grad schrieb:

    Ich will diese Stores jetzt dynaisch erzeugen mit new CStore(12). Wenn ich damit fertig bin reicht ein einfaches delete? Oder muss ich einen Destructor schreiben indem m_sequences.clear() aufgerufen wird, oder muss ich jedes char-Array auch noch vernichten?
    Schonmal vielen Danke

    Lässt sich nicht ohne weiteres beantworten.
    Generell:
    Objekte die nicht dynamisch erzeugt worden sind werden dann zerstört (Destruktor wird aufgerufen). Hast du in deiner Klasse was mit new erzeugt, musst du im Destruktor der Klasse auch ein delete machen.

    In deinem Fall:
    kommt es drauf an was in m_sequences drin stehen wird. Spontan (ich kenne ja nicht genau den Anwendungsfall) würd ich sagen: nimm ein std::string anstelle von char*. Da musst du dich um nichts kümmern.
    Der Destruktor des vectors wird Objekte aus dem vector entfernen und ihren Destruktor aufrufen. Das funktioniert nicht, wenn du Zeiger drin hast.
    Probelme: wem gehören die Zeiger?
    Deshalb: std::string benutzen, falls möglich.



  • okay hört sich sinnvoll an string zu verwenden. Ich muss es zwar ganz am schluss wieder als char* schreiben aber dass macht ja nix.

    Aber was mich jetzt stört ist ein größeres problem:

    ich habe einen vector erstellt mit

    vector<Store*> stores; das soll der hauptcontainer meiner Stores sein. Dieses Teil erstelle ich in einer Klasse die für das einlesen zuständig ist. Danach soll aber der eingelese stores-vector an einer andere klasse angeheftet werden die einen void* pointer bietet (kann ich nix dran ändern).

    Muss ich dann mit memcpy arbeiten um das ding fest an den void* pointer zu binden?



  • p.s.

    ist es korrekt, dass wenn eine lokale Variable auf dem heap herzeugt wird, diese auch nach beendung der funktion existiert?

    Ergo wäre eine Übergabe an einen void* Pointer machbar?

    ist das OK so?

    vector<Store> v;
    anderes_object.voidpointer =v;
    vector<RnaStore*> sequences;
    for (lese_alle_eingaben){
    Store s = new Store(parameter);
    v.add(s);
    }
    


  • wolf.grad schrieb:

    ist das OK so?

    vector<Store> v;
    anderes_object.voidpointer =v;
    vector<RnaStore*> sequences;
    for (lese_alle_eingaben){
    Store s = new Store(parameter);
    v.add(s);
    }
    

    Das könnte in die Hose gehen wenn es denn komplett so aussähe

    void foo()
    {
      vector<Store> v;
      anderes_object.voidpointer =&v;
      vector<RnaStore*> sequences;
      for (lese_alle_eingaben)
      {
        Store s = new Store(parameter);
        v.add(s);
      }
    }
    

    wenn du den foo scope verlässt, wird ein lokal erstelltes objekt AFAIK gelöscht. Wenn du sowas machen möchtest solltest du schon mit new arbeiten.



  • guten morgen,

    sehr schön jetzt hab ichs verstanden. Ich muss new und delete verwenden...

    Aber ich bau mir jetzt eh ein eigenes Object, dass den vector wrappt. Dann kann ich da im destructor durch den vector itern und für jede referenz selber den destructor aufrufen. Dann sollte ich ja auf der sicheren seite sein?

    Ist das ein valider coding style? Ich tue mir gerade unglaublich schwer mich an irgendwelche coding convention in c++ zu halten. Da wohl jeder für sich selber entscheidet wie er mit Speicher umgeht.

    Was ist den unter "gehören die Zeiger" zu verstehen was vorhin von ihoernchen gesagt wurde? Also ein Object liegt auf dem heap und 2 sachen zeigen drauf, einer zerstört es und beim anderen knallts? Dann muss ich doch einer sicherstellen, dass die Zeiger danach nicht mehr verwendet werden? Das ist ja nix anderes als in java wenn ich was auf null setzte verwende ich es ja danach auch ncihtmehr. Also muss man nur beim coden aufpassen? Oder ist das wieder ein schlechter Style????

    Danke


  • Mod

    Ich würde keinen normalen Zieger verwenden, sondern Smart-Pointer. Dann wird automatisch delete aufgerufen wenn die letzte Referenz des Zeigers verschwindet.



  • Das mit den smartpointern würde ich auch empfehlen. Überhaupt würde ich jeden C++ Programmierer die Boost Bibliothek ans Herz legen.

    wolf.grad schrieb:

    Ist das ein valider coding style? Ich tue mir gerade unglaublich schwer mich an irgendwelche coding convention in c++ zu halten. Da wohl jeder für sich selber entscheidet wie er mit Speicher umgeht.

    Das ist das etwas schwierige am C++, da gibts keinen Müllsammler. Man kanns als Vor- oder Nachteil sehen. Prinzipell sind pointer immer ein Ansatzpunkt für fehler. Daher eben die Empfehlung Smartpointern zu benutzen.
    Falls du Pointer wirklich händisch verwendest, achte immer darauf nach dem delete den Wert auch auf NULL zu setzen.

    MyObject * myObject = new MyObject();
    delete myObject;
    myObject = NULL;
    

    Das führt zumindest dazu das man den myObject Zeiger auf NULL prüfen kann um zu schauen ob man auf gelöschten Speicherbereich zugreift. Problematisch wirds erst wenn noch andere Zeiger mal auf MyObject gezeigt haben. Diese merken nämlich nicht ob das Objekt dahinter gelöscht wurde. Wo wir wieder bei Smartpointern wären. Die merken sowas nämlich und sind dann Automatisch NULL.



  • okay das macht sinn. Ich werde jedoch für dieses project auf smartpointer verzichten um ein bisschen was zu lernen (sonst wärs ja fast wie java, und ich will ja meine negative einstellung gegen c++ abbauen 🙂 ). Hier ist kein Geld involviert also kann es auch ruhig mal an ein paar Stellen krachen.

    Ich möchste mich nur auf jeden Fall an Coding Conventionen halten, die man verwendet wenn man selber mit Zeigern arbeitet.

    p.s kann man boost auch mit alten compilern verwenden? Ich muss mit dem visual c++ 6 arbeiten, da sind sachen manchmal sehr umständlich...



  • Ich denke es sollte mit den Compiliern keine Probleme geben. Aber sicher sein kann man da bei Software nie.


Log in to reply