Ich frage mich nur, ob ich std::size_t
stattdessen für Loops und andere Dinge verwenden soll 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 hinsichtlich des Verwendungszwecks std::size_t
?
size_t
wenn Sie führen können , sollten Sicherheitslücken .ssize_t
für signierte Werte.size_t
ist der Ergebnistyp dessizeof
Operators.Verwenden Sie diese Option
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 andere Ganzzahl.Die Verwendung
size_t
zur Darstellung einer Größe in Bytes hilft außerdem dabei, den Code portabel zu machen.quelle
Der
size_t
Typ soll die Größe von etwas angeben , so dass es natürlich ist, es zu verwenden, z. B. die Länge einer Zeichenfolge abzurufen und dann jedes Zeichen zu verarbeiten:Sie müssen natürlich auf Randbedingungen achten, da es sich um einen vorzeichenlosen Typ handelt. Die Grenze am oberen Ende ist in der Regel nicht so wichtig , da die maximalen in der Regel groß ist (obwohl es ist möglich , es zu bekommen). Die meisten Leute verwenden nur eine
int
für solche Dinge, weil sie selten Strukturen oder Arrays haben, die groß genug werden, um die Kapazität davon zu überschreitenint
.Aber achten Sie auf Dinge wie:
Dies führt aufgrund des Umbruchverhaltens vorzeichenloser Werte zu einer Endlosschleife (obwohl ich gesehen habe, dass Compiler davor warnen). Dies kann auch gelindert werden durch: (etwas schwerer zu verstehen, aber zumindest immun gegen Verpackungsprobleme):
Durch Verschieben des Dekrements in einen Nebeneffekt der Fortsetzungsbedingung nach der Überprüfung wird der Wert vor dem Dekrementieren auf Fortsetzung überprüft , es wird jedoch weiterhin der dekrementierte Wert innerhalb der Schleife verwendet (weshalb die Schleife
len .. 1
nicht ausgeführt wirdlen-1 .. 0
).quelle
strlen
jede Iteration einer Schleife aufzurufen . :) Sie können so etwas tun:for (size_t i = 0, len = strlen(str); i < len; i++) ...
for (size_t i = strlen (str); i --> 0;)
-->
Operators "geht an" gefällt (siehe stackoverflow.com/questions/1642028/… ). Haben Sie Ihren Vorschlag in die Antwort aufgenommen.if (i == 0) break;
am Ende der for-Schleife machen (zfor (size_t i = strlen(str) - 1; ; --i)
. B. (Ich mag Ihre zwar besser, frage mich aber nur, ob dies genauso gut funktionieren würde).Per Definition
size_t
ist das Ergebnis dessizeof
Operators.size_t
wurde erstellt, 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
?int
, oderunsigned int
sollte in Ordnung sein.Natürlich ist es auch relevant, was Sie
i
innerhalb der Schleife tun . Wenn Sie es an eine Funktion übergeben, dieunsigned int
beispielsweise eine Auswahl übernimmtunsigned int
.In jedem Fall empfehle ich, implizite Typkonvertierungen zu vermeiden. Machen Sie alle Typkonvertierungen explizit.
quelle
size_t
ist eine sehr lesenswerte Methode, um die Größe 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 undsize_t
- etwas, dasunsigned int
möglicherweise nicht funktioniert (z. B. wann sollten Sie verwendenunsigned long
quelle
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 nicht signierten Typs.
Beispiel:
Das signierte Äquivalent von
size_t
istptrdiff_t
nichtint
.int
In den meisten Fällen ist die Verwendung jedoch immer noch viel besser als size_t.ptrdiff_t
istlong
auf 32- und 64-Bit-Systemen.Dies bedeutet, dass Sie immer zu und von size_t konvertieren müssen, wenn Sie mit einem std :: -Container interagieren, der nicht sehr schön ist. Auf einer laufenden nativen Konferenz erwähnten die Autoren von c ++ jedoch, dass das Entwerfen von std :: vector mit einer vorzeichenlosen Größe_t ein Fehler war.
Wenn Ihr Compiler Sie bei impliziten Konvertierungen von ptrdiff_t nach size_t warnt, können Sie dies mit der Konstruktorsyntax explizit machen:
Wenn Sie nur eine Sammlung iterieren möchten, ohne Grenzen zu überschreiten, verwenden Sie den Bereich basierend auf:
Hier einige Worte von Bjarne Stroustrup (C ++ - Autor), wie man einheimisch wird
Für einige Leute ist dieser signierte / nicht signierte Designfehler in der STL Grund genug, nicht den std :: vector zu verwenden, sondern eine eigene Implementierung.
quelle
for(int i = 0; i < get_size_of_stuff(); i++)
. Nun, sicher, Sie möchten vielleicht nicht viele Raw-Loops machen, aber - komm schon, Sie verwenden sie auch.x + 1 < y
äquivalent zux < y - 1
, aber sie sind nicht mit nicht berichtigenden ganzen Zahlen. Dies kann leicht zu Fehlern führen, wenn Dinge transformiert werden, von denen angenommen wird, dass sie gleichwertig sind.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_type
, die zum Indizieren und Zählen von Vektorelementen verwendet werden sollten.In der Praxis handelt es sich normalerweise um nicht signierte Ints, dies kann jedoch nicht garantiert werden, insbesondere wenn benutzerdefinierte Allokatoren verwendet werden.
quelle
std::size_t
ist dies normalerweiseunsigned long
(8 Bytes auf 64-Bit-Systemen) und nichtunisgned int
(4 Bytes).size_t
, da die Indizes negativ sein können. Man könnte essize_t
für die eigene Instanz eines solchen Arrays verwenden, wenn man jedoch nicht negativ werden möchte.+
für Zeiger entspricht, scheint dies diejenigeptrdiff_t
zu sein, die für Indizes verwendet werden soll.vector<T>::size_type
(und ebenso für alle anderen Container)size_t
betrifft , so ist es eigentlich ziemlich nutzlos, da es effektiv garantiert ist - es ist typisiertAllocator::size_type
und für Einschränkungen in Bezug auf Container siehe 20.1.5 / 4 - insbesonderesize_type
muss seinsize_t
unddifference_type
müssen seinptrdiff_t
. Natürlichstd::allocator<T>
erfüllt der Standard diese Anforderungen. Also benutze einfach die kürzeresize_t
und kümmere dich nicht um den Rest des Loses :)Bald werden die meisten Computer 64-Bit-Architekturen mit 64-Bit-Betriebssystemen sein: Es werden Programme ausgeführt, die auf Containern mit Milliarden von Elementen ausgeführt werden. Dann Sie müssen verwenden ,
size_t
anstattint
als Schleifenindex, sonst wird Ihr Index wird umschlingen am 2 ^ 32: te Element auf beiden 32- und 64-Bit - Systeme.Bereite dich auf die Zukunft vor!
quelle
long int
eher ein als ein brauchtint
. Wenn diessize_t
auf einem 64-Bit-Betriebssystem relevant ist, war es auf einem 32-Bit-Betriebssystem genauso relevant.Seien Sie bei der Verwendung von size_t vorsichtig mit dem folgenden Ausdruck
Sie werden im if-Ausdruck falsch, unabhängig davon, welchen Wert Sie für x haben. Ich habe mehrere Tage gebraucht, um dies zu realisieren (der Code ist so einfach, dass ich keinen Komponententest durchgeführt habe), obwohl es nur wenige Minuten dauerte, um die Ursache des Problems herauszufinden. Ich bin mir nicht sicher, ob es besser ist, einen Cast zu machen oder Null zu verwenden.
Beide Wege sollten funktionieren. Hier ist mein Testlauf
Die Ausgabe: i-7 = 18446744073709551614 (int) (i-7) = - 2
Ich hätte gerne die Kommentare anderer.
quelle
(int)(i - 7)
es sich um einen Unterlauf handelt, derint
anschließend umgewandelt wird, währendint(i) - 7
es sich nicht um einen Unterlauf handelt, da Sie zuersti
in einen konvertierenint
und dann subtrahieren7
. Außerdem fand ich Ihr Beispiel verwirrend.size_t wird von verschiedenen Bibliotheken zurückgegeben, um anzuzeigen, dass die Größe dieses Containers ungleich Null ist. Sie verwenden es, wenn Sie einmal zurück sind: 0
In Ihrem obigen Beispiel ist das Schleifen eines size_t jedoch ein potenzieller Fehler. Folgendes berücksichtigen:
Die Verwendung von Ganzzahlen ohne Vorzeichen kann zu solchen subtilen Problemen führen. Daher bevorzuge ich es, size_t nur zu verwenden, wenn ich mit Containern / Typen interagiere, die dies erfordern.
quelle
size_t
ist ein vorzeichenloser Typ, der den maximalen ganzzahligen Wert für Ihre Architektur enthalten kann. Er ist daher vor ganzzahligen Überläufen aufgrund von Vorzeichen (vorzeichenbehaftetes int,0x7FFFFFFF
erhöht um 1 ergibt -1) oder kurzer Größe (vorzeichenloses kurzes int 0xFFFF, erhöht um 1) geschützt 0).Es wird hauptsächlich in der Array-Indizierung / Schleifen / Adress-Arithmetik usw. verwendet. Funktionen wie
memset()
und werdensize_t
nur akzeptiert , da Sie theoretisch möglicherweise einen Speicherblock mit einer Größe haben2^32-1
(auf einer 32-Bit-Plattform).Für solche einfachen Schleifen stören Sie nicht und verwenden Sie nur int.
quelle
size_t ist ein vorzeichenloser Integraltyp, der die größte Ganzzahl auf Ihrem System darstellen kann. Verwenden Sie es nur, wenn Sie sehr große Arrays, Matrizen usw. benötigen.
Einige Funktionen geben ein size_t zurück und Ihr Compiler warnt Sie, wenn Sie versuchen, Vergleiche durchzuführen.
Vermeiden Sie dies, indem Sie einen geeigneten signierten / nicht signierten Datentyp verwenden oder einfach für einen schnellen Hack typisieren.
quelle
size_t ist int ohne Vorzeichen int. Wann immer Sie unsigned int möchten, können Sie es verwenden.
Ich benutze es, wenn ich die Größe des Arrays angeben möchte, Zähler ect ...
quelle
size_t
um eine vorzeichenlose 64-Bit-Ganzzahl handeln, während es sich bei einem 32-Bit-Computer nur um eine vorzeichenlose 32-Bit-Ganzzahl handelt.