2009-05-11 14 views
2

Ich versuche, ein Array von Klassenobjekten zu erstellen, die ein Integer-Argument verwenden. Ich kann nicht sehen, was mit diesem einfachen kleinen Code nicht stimmt. Könnte jemand helfen?Benötigen Sie Hilfe beim Erstellen eines Arrays von Objekten

#include <fstream> 
#include <iostream> 
using namespace std; 

typedef class Object 
{ 
int var; 
public: 
Object(const int& varin) : var(varin) {} 
} Object; 

int main (int argc, char * const argv[]) 
{ 
for(int i = 0; i < 10; i++) 
{ 
    Object o(i)[100]; 
} 

return 0; 
} 

Antwort

8

In C++ müssen Sie nicht typedef s für class es und struct s. Also:

class Object 
{ 
int var; 
public: 
Object(const int& varin) : var(varin) {} 
}; 

Auch beschreibende Namen sind immer preferrable, ist Object viel missbraucht.

int main (int argc, char * const argv[]) 
{ 
int var = 1; 

Object obj_array[10]; // would work if Object has a trivial ctor 

return 0; 
} 

Ansonsten in Ihrem Fall:

int main (int argc, char * const argv[]) 
{ 
int var = 1; 

Object init(var); 
Object obj_array[10] = { var, ..., var }; // initialize manually 

return 0; 
} 

Obwohl, eigentlich sollte man sucht vector

#include <vector> 
int main (int argc, char * const argv[]) 
{ 
int var = 1; 

vector<Object> obj_vector(10, var); // initialize 10 objects with var value 

return 0; 
} 
4

dirkgently Überblick der ist ziemlich genaue Darstellung von Arrays von Elementen in C++, aber wo Er initialisiert alle Elemente in dem Array mit dem gleichen Wert, der aussieht, als ob Sie versuchen, jedes mit einem bestimmten Wert zu initialisieren.

Um Ihre Frage zu beantworten, erstellen Sie ein Array von Objekten, die einen int-Konstruktorparameter verwenden. Sie können nicht, Objekte werden erstellt, wenn das Array zugewiesen ist und in Ermangelung eines trivialen Konstruktors wird der Compiler beschweren. Sie können jedoch ein Array von Zeigern zu Ihrem Objekt initialisieren, aber Sie erhalten wirklich viel mehr Flexibilität mit einem Vektor, so dass meine folgenden Beispiele std :: vector verwenden.

Sie müssen jedes Objekt separat initialisieren, wenn Sie möchten, dass jedes Objekt einen bestimmten Wert hat, können Sie dies auf zwei Arten tun; auf dem Stapel oder auf dem Haufen. Schauen wir zuerst auf den Stapel.

Jeder Konstruktor, der ein einzelnes Argument akzeptiert und nicht als explicit markiert ist, kann als impliziter Konstruktor verwendet werden. Dies bedeutet, dass an jeder Stelle, an der ein Objekt dieses Typs erwartet wird, stattdessen eine Instanz des einzelnen Parametertyps verwendet werden kann. In diesem Beispiel erstellen wir einen Vektor Ihrer Objektklasse und fügen 100 Objekte hinzu (push_back fügt Elemente zu einem Vektor hinzu). Wir übergeben eine Ganzzahl an push_back, die implizit ein Objekt erzeugt, das in der Ganzzahl übergeben wird.

#include <vector> 
int main() { 
    std::vector<Object> v; 

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

Oder darüber explizit sein:

#include <vector> 
int main() { 
    std::vector<Object> v; 

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

In diesen Beispielen alle Objekte Objekte zugeordnet sind, auf dem Stapel im Rahmen der for-Schleife, so geschieht eine Kopie, wenn das Objekt wird in den Vektor geschoben. Das Kopieren einer großen Anzahl von Objekten kann zu Leistungsproblemen führen, insbesondere wenn Ihr Objekt teuer zu kopieren ist.

Ein Weg, um dieses Leistungsproblem zu erhalten ist, die Objekte auf dem Heap und speichern Zeiger auf die Objekte in Ihrem Vektor zuzuordnen:

#include <vector> 
int main() { 
    std::vector<Object*> v; 

    for(int i = 0; i < 100; i++) { 
     v.push_back(new Object(i)); 
    } 

    for(int i = 0; i < 100; i++) { 
     delete v[i]; 
    } 
} 

Da unsere Objekte auf dem Heap erstellt wurden, stellen wir sicher, müssen dass wir sie löschen, um ihren Dekonstruktor aufzurufen, und ihren Speicher freigeben, tut dieser Code das in der zweiten Schleife.

Manuell aufrufen delete hat seine eigenen Vorbehalte, wenn Sie diese Zeiger auf anderen Code übergeben, können Sie schnell den Überblick darüber verlieren, wer die Zeiger besitzt und wer sie löschen sollte. Ein einfacher Weg, um dieses Problem zu lösen, ist einen intelligenten Zeiger zu verwenden, um die Lebensdauer des Zeigers zu verfolgen, sieht entweder boost::shared_ptr oder tr1::shared_ptr, die Zeiger mit Referenzzählung sind:

#include <vector> 
int main() { 
    std::vector<shared_ptr<Object> > v; 

    for(int i = 0; i < 100; i++) { 
     Object* o = new Object(i); 
     v.push_back(shared_ptr<Object>(o)); 
    } 
} 

Sie werden bemerken, dass der shared_ptr Konstruktor explizit Dies geschieht absichtlich, um sicherzustellen, dass der Entwickler absichtlich ihren Zeiger in den gemeinsamen Zeiger stopft. Wenn alle Verweise auf ein Objekt freigegeben sind, wird das Objekt automatisch von shared_ptr gelöscht, was uns von der Notwendigkeit befreit, sich um seine Lebensdauer Sorgen zu machen.

+0

Vielen Dank für das Follow-up. Dies war auch eine große Hilfe! – banDedo

0

Wenn Sie bei Arrays bleiben möchten, müssen Sie entweder manuell initialisieren oder den Standardkonstruktor verwenden. Sie können jedoch etwas Kontrolle erhalten, indem Sie einen Konstruktor mit einem Standardargument erstellen. Dies wird vom Compiler als Standardkonstruktor behandelt. Der folgende Code gibt beispielsweise die Zahlen 0, ..., 9 der Reihe nach aus. (Allerdings bin ich nicht sicher, dass der Standard schreibt vor, dass die Objekte im Array müssen, um konstruiert werden. Es könnte die Umsetzung abhängig sein, wobei in diesem Fall die Zahlen in beliebiger Reihenfolge erscheinen.)

#include <iostream> 

using namespace std; 

struct A { 
    int _val; 

    A(int val = initializer()) : _val(val) {} 

    static int initializer() { static int v = 0; return v++; } 
}; 

int main() 
{ 
    A a[10]; 
    for(int i = 0; i < 10; i++) 
     cout << a[i]._val << endl; 
} 
Verwandte Themen