Wann sollte std::size_t verwendet werden?

Lesezeit: 11 Minuten

Wann sollte stdsize t verwendet werden
nha123

Ich frage mich nur, ob ich es verwenden soll std::size_t für Loops und so statt int? Zum Beispiel:

#include <cstdint>

int main()
{
    for (std::size_t i = 0; i < 10; ++i) {
        // std::size_t OK here? Or should I use, say, unsigned int instead?
    }
}

Was ist im Allgemeinen die beste Vorgehensweise in Bezug auf die Verwendung std::size_t?

Eine gute Faustregel ist für alles, was Sie in der Schleifenbedingung mit etwas vergleichen müssen, das natürlich a ist std::size_t selbst.

std::size_t ist der Typ von jedem sizeof expression und as ist garantiert in der Lage, die maximale Größe eines beliebigen Objekts (einschließlich eines Arrays) in C++ auszudrücken. Durch die Erweiterung ist es auch garantiert groß genug für jeden Array-Index, so dass es ein natürlicher Typ für eine Schleife nach Index über ein Array ist.

Wenn Sie nur bis zu einer Zahl zählen, kann es natürlicher sein, entweder den Typ der Variablen zu verwenden, die diese Zahl enthält, oder an int oder unsigned int (wenn groß genug), da diese eine natürliche Größe für die Maschine haben sollten.

  • Das ist erwähnenswert nicht verwenden size_t wann Sie sollten, kann zu Sicherheitslücken führen.

    – BlueRaja – Danny Pflughoeft

    16. Juli 2010 um 16:58 Uhr

  • Int ist nicht nur “natürlich”, sondern das Mischen von signierten und unsignierten Typen kann genauso gut zu Sicherheitsfehlern führen. Vorzeichenlose Indizes sind mühsam zu handhaben und ein guter Grund, eine benutzerdefinierte Vektorklasse zu verwenden.

    – Jo So

    15. Februar 2016 um 1:31 Uhr

  • @JoSo Gibt es auch ssize_t für vorzeichenbehaftete Werte.

    – Verschränkte Schleifen

    14. August 2019 um 20:33 Uhr


  • @EntangledLoops ssize_t hat nicht die volle Bandbreite von size_t. Es ist nur die signierte Variante von was auch immer size_t würde übersetzen in. Das bedeutet, dass nicht der volle Umfang des Speichers nutzbar ist ssize_t und ganzzahlige Überläufe können auftreten, wenn sie von Variablen des Typs abhängen size_t.

    – Thomas

    1. September 2020 um 14:18 Uhr


  • @Thomas Ja, aber ich bin mir nicht sicher, worauf Sie hinaus wollen. Ich meinte nur als Drop-in-Ersatz für int, es ist eine engere semantische Passform. Ihr Kommentar, dass nicht das gesamte Sortiment mit verfügbar ist ssize_t ist wahr, aber es gilt auch für int. Was wirklich zählt, ist die Verwendung des geeigneten Typs für die Anwendung.

    – Verschränkte Schleifen

    8. September 2020 um 23:09 Uhr

size_t ist der Ergebnistyp der sizeof Operator.

Verwenden size_t für Variablen, die die Größe oder den Index in einem Array modellieren. size_t vermittelt Semantik: Sie wissen sofort, dass es sich um eine Größe in Bytes oder einen Index handelt und nicht nur um eine weitere Ganzzahl.

Auch mit size_t die Darstellung einer Größe in Bytes hilft dabei, den Code portabel zu machen.

1646307013 221 Wann sollte stdsize t verwendet werden
paxdiablo

Die size_t Typ soll die angeben Größe von etwas, also ist es natürlich, es zu verwenden, zum Beispiel die Länge einer Zeichenfolge zu erhalten und dann jedes Zeichen zu verarbeiten:

for (size_t i = 0, max = strlen (str); i < max; i++)
    doSomethingWith (str[i]);

Sie tun müssen natürlich auf Randbedingungen achten, da es sich um einen vorzeichenlosen Typ handelt. Die Grenze am oberen Ende ist normalerweise nicht so wichtig, da das Maximum normalerweise groß ist (obwohl es ist möglich, dorthin zu gelangen). Die meisten Leute benutzen einfach ein int für so etwas, weil sie selten Strukturen oder Arrays haben, die groß genug werden, um die Kapazität zu überschreiten int.

Aber achten Sie auf Dinge wie:

for (size_t i = strlen (str) - 1; i >= 0; i--)

was aufgrund des Wrapping-Verhaltens von vorzeichenlosen Werten zu einer Endlosschleife führt (obwohl ich gesehen habe, dass Compiler davor gewarnt haben). Dies kann auch durch Folgendes gemildert werden (etwas schwerer zu verstehen, aber zumindest immun gegen Verpackungsprobleme):

for (size_t i = strlen (str); i-- > 0; )

Durch Verschieben des Dekrements in einen Nebeneffekt der Fortsetzungsbedingung nach der Prüfung führt dies die Prüfung auf Fortsetzung des Werts durch Vor decrement, verwendet aber immer noch den dekrementierten Wert innerhalb der Schleife (weshalb die Schleife von läuft len .. 1 eher, als len-1 .. 0).

  • Übrigens ist es eine schlechte Angewohnheit anzurufen strlen bei jeder Iteration einer Schleife. 🙂 Sie können so etwas tun: for (size_t i = 0, len = strlen(str); i < len; i++) ...

    – musiphil

    10. April 2014 um 20:46 Uhr

  • Selbst wenn es sich um einen vorzeichenbehafteten Typ handelt, müssen Sie auf Randbedingungen achten, vielleicht sogar noch mehr, da ein Überlauf von vorzeichenbehafteten Ganzzahlen ein undefiniertes Verhalten ist.

    – Adrian McCarthy

    14. Mai 2014 um 19:30 Uhr

  • Korrekt herunterzählen geht auf folgende (berüchtigte) Weise: for (size_t i = strlen (str); i --> 0;)

    – Jo So

    14. Februar 2016 um 17:40 Uhr


  • @JoSo, das ist eigentlich ein ziemlich netter Trick, obwohl ich mir nicht sicher bin, ob mir die Einführung von gefällt --> „goes to“-Operator (siehe stackoverflow.com/questions/1642028/…). Habe Ihren Vorschlag in die Antwort aufgenommen.

    – paxdiablo

    15. Februar 2016 um 1:21 Uhr


  • Kannst du ein einfaches machen if (i == 0) break; am Ende der for-Schleife (z. B. for (size_t i = strlen(str) - 1; ; --i). (Mir gefällt deins besser, aber ich frage mich nur, ob das genauso gut funktionieren würde).

    – RastaJedi

    11. August 2016 um 20:08 Uhr

Wann sollte stdsize t verwendet werden
Daniel Daranas

Per Definition, size_t ist das Ergebnis der sizeof Operator. size_t wurde geschaffen, um sich auf Größen zu beziehen.

Bei der Häufigkeit, mit der Sie etwas tun (in Ihrem Beispiel 10), geht es nicht um Größen. Warum also verwenden? size_t? intoder unsigned intsollte in Ordnung sein.

Natürlich ist es auch relevant, was man damit macht i innerhalb der Schleife. Wenn Sie es an eine Funktion übergeben, die eine akzeptiert unsigned intzum Beispiel auswählen unsigned int.

In jedem Fall empfehle ich, implizite Typkonvertierungen zu vermeiden. Machen Sie alle Typumwandlungen explizit.

1646307014 905 Wann sollte stdsize t verwendet werden
Arne

kurze Antwort:

fast nie

lange Antwort:

Wann immer Sie einen Zeichenvektor benötigen, der größer als 2 GB auf einem 32-Bit-System ist. In jedem anderen Anwendungsfall ist die Verwendung eines signierten Typs viel sicherer als die Verwendung eines unsignierten Typs.

Beispiel:

std::vector<A> data;
[...]
// calculate the index that should be used;
size_t i = calc_index(param1, param2);
// doing calculations close to the underflow of an integer is already dangerous

// do some bounds checking
if( i - 1 < 0 ) {
    // always false, because 0-1 on unsigned creates an underflow
    return LEFT_BORDER;
} else if( i >= data.size() - 1 ) {
    // if i already had an underflow, this becomes true
    return RIGHT_BORDER;
}

// now you have a bug that is very hard to track, because you never 
// get an exception or anything anymore, to detect that you actually 
// return the false border case.

return calc_something(data[i-1], data[i], data[i+1]);

Das vorzeichenbehaftete Äquivalent von size_t ist ptrdiff_tnicht int. Aber mit int ist in den meisten Fällen immer noch viel besser als size_t. ptrdiff_t ist long auf 32- und 64-Bit-Systemen.

Dies bedeutet, dass Sie immer zu und von size_t konvertieren müssen, wenn Sie mit einem std::containers interagieren, was nicht sehr schön ist. Aber auf einer laufenden nativen Konferenz erwähnten die Autoren von c++, dass das Entwerfen von std::vector mit einem unsigned size_t ein Fehler war.

Wenn Ihr Compiler Sie bei impliziten Konvertierungen von ptrdiff_t in size_t warnt, können Sie dies mit der Konstruktorsyntax explizit machen:

calc_something(data[size_t(i-1)], data[size_t(i)], data[size_t(i+1)]);

Wenn Sie nur eine Sammlung iterieren möchten, ohne die Grenzen zu überprüfen, verwenden Sie den Bereich basierend auf:

for(const auto& d : data) {
    [...]
}

hier einige Worte von Bjarne Stroustrup (C++-Autor) unter Geht heimisch

Für einige Leute ist dieser signierte/unsignierte Designfehler in der STL Grund genug, nicht den std::vector zu verwenden, sondern stattdessen eine eigene Implementierung.

  • Ich verstehe, woher sie kommen, aber ich finde es trotzdem seltsam, darüber zu schreiben for(int i = 0; i < get_size_of_stuff(); i++). Nun, sicher, Sie möchten vielleicht nicht viele rohe Loops machen, aber – komm schon, du benutzt sie auch.

    – einpoklum

    10. Februar 2016 um 12:56 Uhr

  • Der einzige Grund, warum ich rohe Schleifen verwende, ist, dass die C++-Algorithmusbibliothek ziemlich schlecht entworfen ist. Es gibt Sprachen wie Scala, die eine viel bessere und weiter entwickelte Bibliothek haben, um mit Sammlungen zu arbeiten. Dann ist der Anwendungsfall von Rohschleifen so gut wie eliminiert. Es gibt auch Ansätze, C++ mit einer neuen und besseren STL zu verbessern, aber ich bezweifle, dass dies innerhalb des nächsten Jahrzehnts geschehen wird.

    – Arne

    16. Februar 2016 um 9:48 Uhr


  • Ich bekomme das unsigned i = 0; behaupten (i-1, MAX_INT); aber ich verstehe nicht, warum Sie sagen “wenn ich bereits einen Unterlauf hatte, wird dies wahr”, weil das Verhalten der Arithmetik bei unsigned ints immer definiert ist, dh. das Ergebnis ist das Ergebnis modulo der Größe der größten darstellbaren Ganzzahl. Wenn also i==0, dann wird i– zu MAX_INT und dann wird i++ wieder 0.

    – mabraham

    20. Juli 2016 um 16:44 Uhr


  • @mabraham Ich habe genau hingesehen, und Sie haben Recht, mein Code ist nicht der beste, um das Problem zu zeigen. Normalerweise ist das so x + 1 < y gleichwertig x < y - 1, aber sie sind nicht mit Ganzzahlen ohne Vorzeichen. Das kann leicht zu Fehlern führen, wenn Dinge transformiert werden, von denen angenommen wird, dass sie gleichwertig sind.

    – Arne

    20. Juli 2016 um 17:01 Uhr

1646307014 359 Wann sollte stdsize t verwendet werden
Ofir

size_t ist eine sehr gut lesbare Methode, um die Größendimension eines Elements anzugeben – Länge einer Zeichenfolge, Anzahl der Bytes, die ein Zeiger benötigt usw. Es ist auch plattformübergreifend portierbar – Sie werden feststellen, dass sich 64-Bit und 32-Bit gut mit Systemfunktionen verhalten und size_t – etwas das unsigned int möglicherweise nicht (z. B. wann sollten Sie verwenden unsigned long

  • Ich verstehe, woher sie kommen, aber ich finde es trotzdem seltsam, darüber zu schreiben for(int i = 0; i < get_size_of_stuff(); i++). Nun, sicher, Sie möchten vielleicht nicht viele rohe Loops machen, aber – komm schon, du benutzt sie auch.

    – einpoklum

    10. Februar 2016 um 12:56 Uhr

  • Der einzige Grund, warum ich rohe Schleifen verwende, ist, dass die C++-Algorithmusbibliothek ziemlich schlecht entworfen ist. Es gibt Sprachen wie Scala, die eine viel bessere und weiter entwickelte Bibliothek haben, um mit Sammlungen zu arbeiten. Dann ist der Anwendungsfall von Rohschleifen so gut wie eliminiert. Es gibt auch Ansätze, C++ mit einer neuen und besseren STL zu verbessern, aber ich bezweifle, dass dies innerhalb des nächsten Jahrzehnts geschehen wird.

    – Arne

    16. Februar 2016 um 9:48 Uhr


  • Ich bekomme das unsigned i = 0; behaupten (i-1, MAX_INT); aber ich verstehe nicht, warum Sie sagen “wenn ich bereits einen Unterlauf hatte, wird dies wahr”, weil das Verhalten der Arithmetik bei unsigned ints immer definiert ist, dh. das Ergebnis ist das Ergebnis modulo der Größe der größten darstellbaren Ganzzahl. Wenn also i==0, dann wird i– zu MAX_INT und dann wird i++ wieder 0.

    – mabraham

    20. Juli 2016 um 16:44 Uhr


  • @mabraham Ich habe genau hingesehen, und Sie haben Recht, mein Code ist nicht der beste, um das Problem zu zeigen. Normalerweise ist das so x + 1 < y gleichwertig x < y - 1, aber sie sind nicht mit Ganzzahlen ohne Vorzeichen. Das kann leicht zu Fehlern führen, wenn Dinge transformiert werden, von denen angenommen wird, dass sie gleichwertig sind.

    – Arne

    20. Juli 2016 um 17:01 Uhr

1646307014 406 Wann sollte stdsize t verwendet werden
Peter Alexander

Verwenden Sie std::size_t zum Indizieren/Zählen von Arrays im C-Stil.

Für STL-Container haben Sie (zum Beispiel) vector<int>::size_typedie zum Indizieren und Zählen von Vektorelementen verwendet werden sollte.

In der Praxis handelt es sich normalerweise beide um vorzeichenlose Ints, aber dies ist nicht garantiert, insbesondere wenn benutzerdefinierte Zuweisungen verwendet werden.

  • Mit gcc unter Linux, std::size_t ist gewöhnlich unsigned long (8 Bytes auf 64-Bit-Systemen) statt unisgned int (4 Bytes).

    – Rafak

    23. Dezember 2009 um 10:18 Uhr

  • Arrays im C-Stil werden nicht von indiziert size_t da die Indizes negativ sein können. Könnte man gebrauchen size_t für die eigene Instanz eines solchen Arrays, wenn man jedoch nicht negativ werden möchte.

    – Johannes Schaub – litb

    24. Dezember 2009 um 0:18 Uhr

  • Da die Array-Indizierung im C-Stil der Verwendung des Operators entspricht + auf Zeiger, so scheint es ptrdiff_t ist derjenige, der für Indizes verwendet wird.

    – Pavel Minaev

    24. Dezember 2009 um 6:58 Uhr

  • Wie für vector<T>::size_type (und dito für alle anderen Container), es ist eigentlich ziemlich nutzlos, weil es effektiv garantiert ist size_t – es ist typdefiniert Allocator::size_typeund für Beschränkungen diesbezüglich in Bezug auf Container siehe 20.1.5/4 – insbesondere size_type muss sein size_tund difference_type muss sein ptrdiff_t. Natürlich die Vorgabe std::allocator<T> erfüllt diese Anforderungen. Verwenden Sie also einfach die kürzere size_t und kümmere dich nicht um den Rest 🙂

    – Pavel Minaev

    24. Dezember 2009 um 7:01 Uhr

  • Ich muss Arrays im C-Stil und negative Indizes kommentieren. ja du kannaber du sollte nicht. Der Zugriff außerhalb der Array-Grenzen ist undefiniert. Und wenn Sie mit Zeigern knifflige Dinge tun, ist es eine verwirrende, schlechte Idee, dies mit einem Array-Index anstelle von Zeigermathematik (und vielen Codekommentaren) zu tun.

    – Zan Luchs

    11. Januar 2017 um 18:16 Uhr

922920cookie-checkWann sollte std::size_t verwendet werden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy