it-swarm.com.de

Sollte ich ein unique_ptr mit einem Array-Typ oder einem Vektor verwenden?

Ich bin seit Jahren nicht mehr in C++, das letzte Mal, als ich es verwendet habe, war es vor C++ 11 wieder im Spieledesign. Ich sehe all diese neuen Zeigertypen, die großartig erscheinen. Aber ich bin mir nicht sicher, wann und wie ich sie verwenden soll. Früher habe ich einen Puffer wie diesen erstellt:

uint bufferSize = 1024;
unsigned char *buffer = (unsigned char*)malloc(bufferSize, sizeof(char));

Es ist nicht schön und ich bin mir ziemlich sicher, dass Neu/Löschen schon damals in C++ eine Sache war, aber ich habe in dieser Zeit nie davon erfahren. Ich denke nicht, dass rohe Zeiger verwendet werden sollten, wenn dies vermeidbar ist, also versuche ich mich daran zu gewöhnen, dies jetzt zu schreiben:

uint bufferSize = 1024;
std::unique_ptr<unsigned char[]> buffer;
buffer = std::make_unique<unsigned char[]>(bufferSize);

Dies wirft jedoch die Frage auf, ob ich die alten Rohzeiger einfach so auf unique_ptr Zuordnen soll. Es gibt auch std::vector, Das für jedes Array viel natürlicher zu sein scheint. Soll ich stattdessen einen Vektor verwenden? Gibt es Faustregeln für die Verwendung des einen oder anderen (für Arrays)?

Um einige spezifischere Informationen hinzuzufügen, erstelle ich ein Spiel und richte einen Bildschirmpuffer zum Zeichnen ein. Ich beginne mit ASCII und werde wahrscheinlich irgendwo im Pixel weitergehen Die Puffergröße muss sich zur Laufzeit nie ändern, aber es wäre schön, wenn ich während der Entwicklung ein wenig mit der Bildschirmgröße spielen könnte. Deshalb deklariere ich nicht einfach ein Array mit fester Länge (meine bufferSize ist es tatsächlich Zwei Konstanten multipliziert (screenWidth und screenHeight). Dies ist nur ein Prototyp, er muss nicht skalierbar oder implementierbar sein, aber ich möchte diese Chance trotzdem nutzen, um zu lernen, wie man besseres C++ schreibt.

4
Kevin

sizeof(TYPE) ist seit jeher eine schlechte Idee in C und C++, vorausgesetzt, Sie könnten sizeof *pointer verwenden. Das Problem ist, dass es die Typinformationen dupliziert, ohne eine Prüfung hinzuzufügen.

In C ist das Casting eines void* Auch eine schlechte Idee, da das Überschreiben der Sprache nur dort erfolgen sollte, wo und wann dies nach sorgfältiger Überlegung erforderlich ist.

Und schließlich akzeptiert malloc() nur ein Argument, Sie möchten stattdessen dort multiplizieren. Ihr Compiler sollte Sie jedoch warnen.

Als nächstes dies:

uint bufferSize = 1024;
unsigned char *buffer = (unsigned char*)malloc(bufferSize * sizeof(char));

Entspricht nicht ganz dem folgenden, abgesehen vom verwendeten Allokator und der automatischen Verwaltung des Puffers:

uint bufferSize = 1024;
auto buffer = std::make_unique<unsigned char[]>(bufferSize);

Der zusätzliche Unterschied ist die Wertinitialisierung, die letztere macht es, die erstere verzichtet darauf.

Ist das wichtig?
Wir können nicht sagen, es hängt von den spezifischen Umständen ab. Vielleicht möchten Sie diese Initialisierung tatsächlich, oder der Compiler kann sie optimieren.

Oder vielleicht passt das Folgende besser zu Ihren Bedürfnissen:

uint bufferSize = 1024;
std::unique_ptr<unsigned char[]> buffer(new unsigned char[bufferSize]);

Alternative mit C++ 20 std::make_unique_default_init() :

uint bufferSize = 1024;
auto buffer = std::make_unique_default_init<unsigned char[]>(bufferSize);

Wie auch immer, std::vector Ist wahrscheinlich einfacher und kann bis auf den gleichen Wert optimiert werden, es sei denn, Sie verwenden etwas wie direkt oben oder Sie müssen den Puffer an Code weitergeben, der einen newed up-Puffer erwartet Code.

4
Deduplicator

Ja, Sie sollten einen std::vector<unsigned char> Für einen Puffer mit statisch unbekannter Größe verwenden. Sie können verwenden auch einen std::array<unsigned char, SIZE> Für einen Puffer mit statisch bekannter Größe, aber Sie haben auch keinen.

Ein Vektor ist ziemlich einfach zu verwenden.

std::vector<unsigned char> buffer(ScreenWidth * ScreenHeight);
// use buffer.data() as you would previously use a unsigned char *

Verwenden Sie nicht std::unique_ptr<unsigned char[]>, new, new[] Oder malloc, da ihre Verwendung ausführlicher ist und nicht performanter ist als die gleichwertige Verwendung von vector und erfordert eine sorgfältige Prüfung, um sicherzustellen, dass Sie nicht versehentlich ein undefiniertes Verhalten erhalten haben. Zum Beispiel haben Sie mit malloc keine unsigned char Erstellt, daher ist jede Verwendung ein undefiniertes Verhalten.

Es kann sich lohnen, einen Typalias zu deklarieren, wenn Sie sich für array entscheiden

constexpr uint ScreenWidth = 1920;
constexpr uint ScreenHeight = 1080;

using ScreenBuffer = std::array<unsigned char, ScreenWidth * ScreenHeight>;
3
Caleth