2013-11-23 16 views
6

In meinem C++ - Code habe ich eine Klasse Object mit einem ID-Feld vom Typ Int ausgestattet. Jetzt möchte ich einen Zeigervektor vom Typ Objekt * erstellen. Zuerst versuchte ichErstellen von C++ - Vektor von Zeigern

vector<Object*> v; 

for(int id=0; id<n; id++) { 
    Object ob = Object(id); 
    v.push_back(&ob); 
} 

aber dies scheiterte, weil hier die gleiche Adresse wiederholt sich nur n-mal. Wenn ich den neuen Operator verwenden würde, würde ich bekommen, was ich will, aber ich möchte dynamische Speicherzuweisung vermeiden. Dann dachte ich, dass ich n verschiedene Zeiger vor der for-Schleife deklariere. Einfache Möglichkeit dazu ist ein Array zu erklären, so dass ich dies tat:

vector<Object*> v; 
Object ar[n]; 

for(int i=0; i<n; i++) { 
    ar[i] = Object(i); 
} 

for(int i=0; i<n; i++) { 
    v.push_back(ar+i); 
} 

Gibt es noch die Möglichkeit einen Speicherverlust zu bekommen, wenn ich es auf diese Weise tun? Auch eine Array-Deklaration zu durchlaufen ist meiner Meinung nach ein wenig ungeschickt. Gibt es andere Möglichkeiten, Vektorzeiger zu erstellen, aber manuelle Speicherverwaltung zu vermeiden?

EDIT: Warum will ich Zeiger statt nur einfache Objekte?

Nun habe ich die ursprüngliche Ist-Situation etwas modifiziert, weil ich dachte, auf diese Weise kann ich die Frage in der einfachsten möglichen Form darstellen. Jedenfalls denke ich immer noch, dass die Frage beantwortet werden kann, ohne zu wissen, warum ich einen Vektor von Zeigern möchte.

Eigentlich habe ich

Class A { 
protected: 
    vector<Superobject*> vec; 
... 
}; 

Class B: public A {...}; 

Class Superobject { 
protected: 
    int id; 
... 
} 

Class Object: public Superobject {...} 

In abgeleiteten Klasse B ich das Mitglied Feld vec mit Objekten des Typs Object füllen möchten. Wenn die Oberklasse keine Zeiger verwendet, hätte ich Probleme mit dem Objekt-Slicing. Also in der Klasse B Konstruktor möchte ich vec als Vektor der Zeiger des Typs Object* initialisieren.

EDIT2

Ja, so scheint es mir, dass die dynamische Zuordnung ist die vernünftige Option und die Idee, ein Array zu verwenden, eine schlechte Idee ist. Wenn das Array den Gültigkeitsbereich verlässt, werden die Dinge schief gehen, weil die Zeiger im Vektor auf Speicherstellen zeigen, die nicht notwendigerweise die Objekte mehr enthalten.

In Konstruktor für Klasse B hatte ich

B(int n) { 
    vector<Object*> vec; 
    Object ar[n]; 

    for(int id=0; id<n; id++) { 
     ar[id] = Object(id); 
    } 

    for(int id=0; id<n; id++) { 
     v.push_back(ar+id); 
    } 
} 

Dieses in Objekten der Klasse B. sehr seltsames Verhalten verursacht

+2

Wenn Sie keine dynamische Speicherzuweisung möchten, warum verwenden Sie Zeiger? Sie können auch mit einem Array von Object arbeiten. –

+1

Warum möchten Sie Zeiger in erster Linie speichern? – Yuushi

+1

Das Problem mit Ihrer zweiten Methode ist, dass es kein legales C++ ist. 'Objekt ar [n];' ist nicht zulässig, es sei denn, n ist eine Konstante. Auch da Sie gemäß Ihrer Bearbeitung eine Klassenhierarchie haben, aber mit 'Object ar [n];' haben Sie nur Objekte, keine Superobjects. Übrigens ist Ihre erste Methode auch falsch, weil Sie die Adressen von Objekten speichern, die zerstört wurden. Ich würde nur dynamische Speicherzuweisung verwenden. – john

Antwort

6

In dieser Schleife:

for(int id=0; id<n; id++) { 
    Object ob = Object(id); 
    v.push_back(&ob); 
} 

Sie erstellen n mal Objektinstanz auf Stapel. Bei jeder Iteration wird ein Element erstellt und entfernt. Sie können dies einfach unter Verwendung der folgenden vermeiden:

for(int id=0; id<n; id++) { 
    Object* ob = new Object(id); 
    v.push_back(ob); 
} 

danke, dass jedes neue Element auf dem Heap nicht auf dem Stapel vorhanden ist. Versuchen Sie, in der Klasse Object-Konstruktor so etwas hinzuzufügen:

std::cout<<"Object ctor()\n"; 

und gleich in der destructor:

std::cout<<"Object dtor()\n"; 

Wenn Sie nicht diese Objekte erstellen möchten, mit „neuen“ versuchen Grund geschrieben von @ woolstar

+0

+1, um den Fehler zu bemerken – Pat

3

Kein kein Speicherleck in Ihrer Version ist. Wenn das Programm den Gültigkeitsbereich verlässt, wird sowohl der Vektor als auch das Array zerstört. Zu Ihrer zweiten Frage: Warum nicht einfach die Objekte direkt in einem Vektor speichern?

vector<Object> v; 

for(int i = 0; i < n; i++) 
{ 
    Object obj = Object(i); 
    v.push_back(obj); 
} 
5

Ihre Frage zu Speicherverlusten lässt mich denken, dass Sie sich Gedanken über den Lebenszyklus und die Bereinigung dieser Objekte machen. Ich ursprünglich vorgeschlagen Wrapper, aber C++ 11 gab uns unique_ptr, und C++ 14 in der fehlenden make_unique gefüllt.So mit allem, was wir tun können:

vector<unique_ptr<SuperObject>> v ; 

Welche Sie an Ort und Stelle mit der Großartigkeit der perfekten Transport- und variadische Vorlagen erstellen,

v.push_back(make_unique<Object>(...)) ; 

Ja, Sie gehen mit einigen Heapzuweisungen leben zu müssen, aber alles wird aufgeräumt, wenn v verschwindet.

Jemand schlug eine Boost-Bibliothek vor, ptr_container, aber das erfordert nicht nur Boost zu Ihrem Projekt hinzufügen, sondern Aufklärung aller zukünftigen Leser, was das ptr_container ist und tut.

+3

Bitte, es sei denn, Sie brauchen shared_ptr Semantik, tun Sie dies nicht. Verwenden Sie einfach http://www.boost.org/doc/libs/1_55_0/libs/ptr_container/doc/ptr_container.html. – KitsuneYMG

Verwandte Themen