2015-01-30 14 views
6

Ich arbeite mit einer Code-Basis, die schlecht geschrieben ist und eine Menge Speicherlecks hat.Ist es eine schlechte Idee, POD C-array mit std :: valarray zu ersetzen?

Es verwendet viele Strukturen, die rohe Zeiger enthalten, die meist als dynamische Arrays verwendet werden.

Obwohl die Strukturen oft zwischen Funktionen übergeben werden, sind die Zuweisung und Freigabe von diesen Zeigern an zufälligen Orten platziert und kann nicht leicht verfolgt/durchdacht/verstanden werden.

Ich habe einige von ihnen in Klassen und diese Zeiger geändert, um von den Klassen selbst behandelt zu werden. Sie funktionieren gut und sehen nicht sehr hässlich aus, abgesehen davon, dass ich die Kopierkonstrukt- und Kopierzuweisung dieser Klassen verboten habe, einfach weil ich keine Zeit damit verbringen möchte, sie zu implementieren.

Jetzt denke ich, erfinde ich das Rad neu? Warum ersetze ich C-array nicht durch std: array oder std :: valarray?

Ich würde std :: valarray bevorzugen, weil es Heap-Speicher und RAIIed verwendet. Und std :: array ist (noch) nicht in meiner Entwicklungsumgebung verfügbar.

Edit1: Ein weiteres Plus von std :: Array ist, dass die Mehrheit dieser dynamischen Arrays POD sind (meist int16_t, int32_t und Schwimmer) Arrays und die numerische API kann Möglichkeit das Leben leichter machen.

Gibt es etwas, auf das ich achten muss, bevor ich beginne?

Einer, den ich mir vorstellen kann ist, dass es nicht eine einfache Möglichkeit gibt, std :: valarray oder std :: array zurück in C-artige Arrays zu konvertieren, und ein Teil unseres Codes verwendet Zeigerarithmetik und Daten müssen sein präsentiert als einfache C-artige Arrays.

Sonst noch etwas?

EDIT 2

Ich kam in this question vor kurzem. Eine sehr schlechte Sache über std::valarray ist, dass es bis C++ 11 nicht sicher kopierbar ist.

Wie in dieser Antwort in C++ 03 und früher zitiert, ist es UB, wenn Quelle und Ziel unterschiedlich groß sind.

+0

Wenn ich es nicht vermisse, bin ich überrascht, dass 'std :: valarray' kein' .data() 'wie' std :: vector' enthält, das das zugrundeliegende rohe Array freigibt, wenn Sie ein C benötigen -Style-Array. – CoryKramer

+6

Aus der Beschreibung, die Sie haben, scheint ein std :: vector geeignet zu sein. Gibt es etwas Bestimmtes, das dir die Beachtung von std :: valarray rechtfertigt? – nos

+2

'std :: valarray' ist/war für LAPACKish-Anwendungen gedacht; Es ist selten benutzt und wahrscheinlich nicht gut hier. 'std :: vector' ist der übliche Container für dynamische Arrays, und Sie können einen Zeiger auf seine Daten mit' & vec [0] 'pre-C++ 11 erhalten (wenn' .data() 'noch nicht verfügbar war). – Wintermute

Antwort

13

Der Standardersatz für C-artige Arrays wäre std::vector. std::valarray ist ein "seltsamer" Mathe-Vektor für Zahlenberechnung. Es ist nicht wirklich entworfen, um ein Array von beliebigen Objekten zu speichern.

Das Gesagte, mit std::vector ist höchstwahrscheinlich eine sehr gute Idee. Es würde Ihre Lecks beheben, den Heap nutzen, ist in der Größe veränderbar, hat eine große Ausnahmesicherheit und so weiter.

Es garantiert auch, dass die Daten in einem zusammenhängenden Speicherblock gespeichert werden. Sie können einen Zeiger auf den Block mit der data() Elementfunktion oder, wenn Sie vor C++ 11 sind, mit &v[0] für einen nicht leeren Vektor v erhalten. Sie können dann wie gewohnt mit dem Zeiger arbeiten.

+0

Nicht zu vergessen, dass mit 'std :: vector', Sie erhalten auch kopieren Semantik, ohne etwas zu tun. Löschen und Kopieren von Konstruktoren und Zuweisungsoperatoren entfällt. – 5gon12eder

+0

@ 5gon12eder Ja, darüber habe ich auch nachgedacht. Aber auf lange Sicht werde ich sie immer noch aus Leistungsgründen verbieten. Es ist keine gute Methode, große numerische Arrays trotzdem tief zu kopieren, und das ist einer der Gründe, warum MATLAB langsam ist. – user3528438

+3

@ user3528438 Nicht kopieren ist (fast) immer schneller als das Kopieren, aber wenn man * kopieren muss, ist es praktisch, die hochoptimierte Implementierung in 'std :: vector' zu verwenden. – 5gon12eder

5

Ich würde std::vector als Ersatz für c-artige Arrays bevorzugen.Sie können einen direkten Zugriff auf die zugrunde liegenden Daten (so etwas wie nackte Zeiger) haben über .data():

Returns Zeiger auf den zugrunde liegenden Array als Speicherelement dient.

6

std::unique_ptr<int[]> ist in der Nähe zu einem Drop-in-Ersatz für eine besitzende int*. Es hat die nette Eigenschaft, dass es nicht implizit selbst kopieren wird, aber es wird sich implizit bewegen.

Eine Operation, die Kopien erzeugt, wird anstelle von Laufzeit-Ineffizienz Kompilierungszeitfehler generieren.

Es hat auch fast keine Laufzeit Overhead über die Besitzer int* anders als eine Null-Prüfung bei der Zerstörung. Es nutzt nicht mehr Platz als ein int*.

std::vector<int> speichert 3 Zeiger und implizit kopiert (das kann teuer sein und stimmt nicht mit Ihrem vorhandenen Codeverhalten überein).

Ich würde mit std::unique_ptr<int[]> als ersten Durchlauf beginnen und es zum Funktionieren bringen. Ich übersetze vielleicht etwas Code zu std::vector<int>, nachdem ich entscheide, dass intelligentes Puffermanagement es wert ist.

Eigentlich würde ich als ersten Durchlauf nach memcpy und memset und ähnlichen Funktionen suchen und sicherstellen, dass sie nicht auf den fraglichen Strukturen arbeiten, bevor ich anfange, RAII-Mitglieder hinzuzufügen.

Ein std::unique_ptr<int[]> bedeutet, dass der standardmäßig erstellte Destruktor für eine Struktur die RAII-Bereinigung für Sie durchführt, ohne dass Sie einen neuen Code schreiben müssen.

+0

Können Sie weiter erklären, warum Sie nach memcpy und memset suchen würden? Liegt es daran, dass memcpy (struct * to, struct * from, sizeof (struct)) sehr unsicher ist, wenn struct in eine RAII-Klasse umgewandelt wird? – user3528438

+2

@ user3528438 ja.'memset' zu löschen,' memcpy' zu kopieren, usw. - all dies sind gängige Mikrooptimierungen im C-style-Code und werden den RAII-Klassen (in der Praxis) und undefiniertem Verhalten (in der Theorie) fatal schaden. – Yakk