2009-08-11 4 views
1

einzustellen Ich mache ein Projekt, das einige Pascal (Delphi) -Code in C++ konvertiert und möchte eine Funktion schreiben, die in etwa dem Pascal "SetLength" entspricht Methode. Dies bezieht sich sowohl auf ein dynamisches Array als auch auf eine Länge und weist den Speicher zu und gibt die Referenz zurück.Eine generische Methode, um die Länge eines dynamischen Arrays beliebigen Typs in C++

In C++ Ich ist

void* setlength(void* pp, int array_size, int pointer_size, int target_size, ....) { 
     void * p; 
     // Code to allocate memory here via malloc/new 
     // something like: p = reinterpret_cast<typeid(pp)>(p); 
     //     p=(target_size) malloc(array_size); 
     return p; 
} 

Meine Frage nach dem Vorbild der

von etwas denken dies: Gibt es einen Weg, um den Zeigertyp auf eine Funktion wie diese passieren und den Speicher erfolgreich zuweisen zu (vielleicht über ein Typid-Parameter?)? Kann ich

<reinterpret_cast> 

irgendwie? Das ultimative Ziel wäre so etwas wie die folgenden in Bezug auf die Nutzung sein:

float*** p; 
p=setlength(100,sizeof(float***),sizeof(float**),.....); 

class B; 
B** cp; 
cp=setlength(100,sizeof(B**),sizeof(B*),.....); 

Jede Hilfe sehr willkommen sein würde. Ich bin mir bewusst, dass mein vorgeschlagener Code falsch ist, wollte aber die allgemeine Idee vermitteln. Vielen Dank.

Antwort

5

Verwenden Sie std :: vector anstelle von Raw-Arrays. Dann können Sie einfach seine resize() Member-Methode aufrufen.

und die Funktion eine Vorlage machen, um beliebige Arten zu behandeln:

Wenn Sie Ihre Funktion nutzen wollen, könnte es in etwa so aussehen:

template <typename T> 
std::vector<T>& setlength(std::vector<T>& v, int new_size) { 
     v.resize(new_size); 
     return v; 
} 

Aber jetzt ist es so einfach, Sie wollen vielleicht Beseitigen Sie die Funktion vollständig und rufen Sie einfach zuerst resize an.

Ich bin nicht ganz sicher, was Sie mit den Dreifach-Zeigern in Ihrem Beispiel zu tun versuchen, aber es sieht so aus, als ob Sie nicht die Größe ändern möchten, die Sie auf eine bestimmte Größe initialisieren möchten durchgeführt wird mit dem vector Konstruktor:

std::vector<float>v(100); 
1

Für ein mehrdimensionales Array, wahrscheinlich die beste Option wäre multi_array Bibliothek verwenden die boost:

typedef boost::multi_array<float, 3> array_type; 
array_type p(boost::extents[100][100][100]); // make an 100x100x100 array of floats 
p[1][2][3] = 4.2; 

Auf diese Weise können Sie die Zuordnung und Details zum Einstellen des mehrdimensionalen Arrays vollständig abstrahieren up. Da der lineare Speicher verwendet wird, profitieren Sie von den Effizienzvorteilen des linearen Speichers durch den einfachen Zugriff auf die Umleitungen.

Andernfalls haben Sie drei andere wichtige Optionen.

Die C++ - wäre es, einen STL-Container verwenden y Option ohne externe Bibliotheken zu verwenden:

std::vector<float **> p; 
p.resize(100); 

Wie bei multi_array wird p dann automatisch freigegeben werden, wenn sie den Gültigkeitsbereich verlässt. Sie können die Vektorgrenzen mit p.size() erhalten. Allerdings wird der Vektor nur eine Dimension für Sie behandeln, also werden Sie am Ende verschachtelte Vektoren machen (ick!).

Sie können auch new direkt verwenden:

float ***p = new float**[100]; 

ausplanen:

delete [] p; 

Diese alle Nachteile std::vector hat, und es wird nicht für Sie frei, und Sie können‘ t die Größe später bekommen.

Die obigen drei Methoden werden alle eine Ausnahme vom Typ std::bad_alloc auslösen, wenn sie nicht genügend Speicher zuordnen können.

schließlich der Vollständigkeit halber gibt es die C Route, mit calloc():

float ***p = (float ***)calloc(100, sizeof(*p)); 

zu befreien:

free((void*)p); 

Das von C kommt und ist ein bisschen hässlicher mit allen Würfe. Für C++ - Klassen werden die Konstruktoren auch nicht für Sie aufgerufen.Außerdem wird nicht überprüft, ob die Größe des Arguments mit der Besetzung übereinstimmt.

Wenn calloc() Speicher nicht reservieren kann, wird NULL zurückgeben; Sie müssen dies überprüfen und damit umgehen.

+1

Ich würde sicherlich nicht sagen, Monstrositäten, sie geben eine viel intuitivere Zugriff auf mehrdimensionale Datenstrukturen. Davon abgesehen, können Sie etwas Leistung im Vergleich zu einer linearen Dimension, auf die zugegriffen wird, zuerst verlieren. – DeusAduro

+0

Dies ist, was ich im Moment benutze, aber fragte mich, ob es eine Möglichkeit gäbe, alle Ausnahmeregelungen an einer Stelle bei der Zuweisung zu platzieren. Meine Anwendung verwendet viele 3D-Arrays, wo dreifache Indirektion (leider) notwendig ist –

+0

viel intuitiver als was? – jalf

0

der neue Betreiber selbst ist im wesentlichen, was Sie fordern, mit der Ausnahme, dass für Doppel/Dreifach-Zeiger entsprechend zuweisen Sie etwas entlang der folgenden Zeilen tun müssen:

float** data = new float*[size_of_dimension_1]; 
for (size_t i=0 ; i<size_of_dimension_1 ; ++i) 
    data[i] = new float[size_of_dimension_2]; 

... 

// to delete: 
for (size_t i=0 ; i<size_of_dimension_1 ; ++i) 
    delete [] data[i]; 
delete [] data; 

Edit: Ich würde vorschlagen, eine der vielen C++ - Mathematik/Matrix-Bibliotheken da draußen zu verwenden. Ich würde vorschlagen, uBlas.

+0

Ja, das ist, wie ich habe sie gemacht, aber für jeden Typ muss eine neue Schleife geschrieben werden (dh eine für ein 3D-Array von Floats, eine für ein 3D-Array von Klassenobjekten ...). Ich bin etwas betroffen von der Tatsache, dass ich einen Übersetzungsjob mache, anstatt von Grund auf neu. –

2

Wenn Sie es buchstäblich tun wollten, würden Sie es wie folgt tun:

template <typename T> 
T* SetLength(T* arr, size_t len) { 
    return static_cast<T*>(realloc(arr, sizeof(T) * len)); 
} 

Beachten Sie, dass das Array Muss haben mit malloc oder calloc zugeordnet. Beachten Sie auch, dass dadurch die Größe des Arbeitsspeichers nicht geändert wird. Der Arbeitsspeicher wird freigegeben und Speicher mit der entsprechenden Größe neu zugewiesen. Wenn andere Zeiger auf das Array übergeben wurden, sind sie danach ungültig.

Sie sind wirklich besser dran mit einer idiomatischen C++ - Lösung, wie std::vector.

0

dies die C++ Art und Weise zu tun:

1) Wie JALF erwähnt, bevorzugen std :: vector, wenn Sie
2) nicht void * p tun Sie. Bevorzugen Sie stattdessen, um Ihre Funktion eine Vorlage des Typs T.