2016-08-22 5 views
0

So schreibe mir eine Klasse, die 1d-Arrays und 2d-Arrays hat, dass ich in dem Konstruktor dynamisch zuteilenVerwenden Sie std :: vector für dynamisch zugewiesene 2d-Array?

class Foo{ 
int** 2darray; 
int * 1darray; 
}; 

Foo::Foo(num1, num2){ 

2darray = new int*[num1]; 
for(int i = 0; i < num1; i++) 
{  
    array[i] = new int[num2]; 
} 
1darray = new int[num1]; 
} 

Dann werde ich jedes 1d-Array und jedes Array in dem 2D-Array löschen muß im Destruktor, richtig? Ich möchte Std :: Vector dafür nicht tun. Gibt es einen Nachteil, dies zu tun? (macht die Kompilierung langsamer etc?)

TL; DR: wann std :: vector für dynamisch zugewiesene Arrays, die während der Laufzeit NICHT angepasst werden müssen?

+5

IMHO * dynamisch zugewiesenen Arrays * gleich 'std :: VECTOR'.Ich versuche, so weit wie möglich von manuellen Speicherzuweisungen fernzubleiben. – NathanOliver

+0

Verwenden Sie immer 'std :: vector', es sei denn, Sie wissen zum Zeitpunkt der Kompilierung wirklich, wie groß Ihr Array sein wird. Selbst dann möchten Sie vielleicht einen Standardcontainer verwenden (sagen wir ein Bitset, wenn Sie eine Sammlung von Flags haben wollen). Für die meisten Anwendungsfälle entspricht ein 'std :: vector ', der während der Laufzeit nicht die Größe ändert, einem 'Type []'. –

+0

BTW, verwende keinen Vektor von Vektoren, verwende auch 1D Vektor für den 2D Fall. – Ped7g

Antwort

3

vector ist in Ordnung für die überwiegende Mehrheit der Anwendungen. Von Hand abgestimmte Szenarios sollten zuerst versuchen, den Zuordner einzustellen und erst dann den Container zu ändern. Die Korrektheit des Speichermanagements (und Ihres Programms im Allgemeinen) ist viel wertvoller als jede Kompilierungszeit.

Mit anderen Worten, vector sollte Ihr Ausgangspunkt, und bis Sie es unbefriedigend sein, Sie über etwas anderes nicht kümmern sollte.

Als zusätzliche Verbesserung sollten Sie einen 1-dimensionalen vector als Back-End-Speicher verwenden und nur eine zweidimensionale indizierte Ansicht bereitstellen. Dieses Szenario kann die Cache-Lokalität und die Gesamtleistung verbessern und einige Vorgänge wie das Kopieren der gesamten Struktur erleichtern.


die zweite von zwei Parametern, die Vorlage vector, der standardmäßig auf einen Standard-Zuordner für eine gegebene Art akzeptiert.

+0

danke für die Einsicht. Könntest du erklären, wann du den Allokator benutzen musst? – kassio

+2

@qeia Wenn Sie fragen müssen, wann Sie es brauchen, müssen Sie es nicht anpassen. –

2

Es sollte keine Nachteile geben, da vector zusammenhängenden Speicher garantiert. Aber wenn die Größe festgelegt ist und 11 ist verfügbar ++ C vielleicht ein array unter anderen Optionen:

  • es nicht erlaubt
  • je nach Größe ändern, wie die vector initialisiert verhindert Umverteilungen
  • Größe ist hartcodiert in den Anweisungen (Template-Argument). Siehe Ped7g Kommentar für eine detailliertere Beschreibung
+1

Vorsicht, warum der Downvote? –

+0

Kein Downvoter, nur ein Kommentator: "Garantien", keine "Garantien". Erläutern Sie auch Ihre qualifizierte Aussage, dass Array eine bessere Option ist. –

+2

@Boris: weil mit 'std :: array' die Größe in Anweisungen fest codiert ist (Größe ist Vorlagenparameter). Das ist IMO-Randgewinn die meiste Zeit, und wenn es von vielen unterschiedlich großen Arrays verwendet wird, wird der Code Bloat wahrscheinlich mehr Schaden anrichten. Aber das ist nur meine unqualifizierte Annahme (Sie müssen den tatsächlichen Code profilieren, um eine qualifizierte Meinung dazu zu haben :)). Aber bei 2D-Arrays (geschrieben als 1D) kann ein hartcodiertes '* rowsize' von Vorteil sein, vor allem bei Potenzen von 2 Größen (auf modernen x86 wird es sehr wahrscheinlich keine Rolle spielen und willkürliches' mul' ist in Ordnung). – Ped7g

0

Ein 2D-Array ist kein Array von Zeigern. Wenn Sie dies so definieren, kann jede Zeile/Spalte eine andere Größe haben. Außerdem sind die Elemente nicht im Speicher abgelegt. Dies kann zu einer schlechten Performance führen, da der Prefetcher Ihre Zugriffsmuster nicht wirklich gut vorhersagen kann. Daher ist es nicht ratsam, std :: vectors ineinander zu verschachteln, um mehrdimensionale Arrays zu modellieren. Ein besserer Ansatz besteht darin, einen fortlaufenden Speicherabschnitt auf einen mehrdimensionalen Speicherbereich zuzuordnen, indem benutzerdefinierte Zugriffsmethoden bereitgestellt werden.

Sie können im Browser testen: http://fiddle.jyt.io/github/3389bf64cc6bd7c2218c1c96f62fa203

#include<vector> 

template<class T> 
struct Matrix { 
    Matrix(std::size_t n=1, std::size_t m=1) 
    : n{n}, m{m}, data(n*m) 
    {} 

    Matrix(std::size_t n, std::size_t m, std::vector<T> const& data) 
    : n{n}, m{m}, data{data} 
    {} 

    //Matrix M(2,2, {1,1,1,1}); 

    T const& operator()(size_t i, size_t j) const { 
    return data[i*m + j]; 
    } 

    T& operator()(size_t i, size_t j) { 
    return data[i*m + j]; 
    } 

    size_t n; 
    size_t m; 
    std::vector<T> data; 
    using ScalarType = T; 
}; 

Sie Operator implementieren können [] durch einen VectorView Rückkehr, die Zugriff auf die Daten einen Index und die Abmessungen hat.