Wir verwenden die meiste Zeit den Integer-Typ, der Indexvariablen darstellt. Aber in einigen Situationen sind wir gezwungen zu wählen
std::vector<int> vec;
....
for(int i = 0; i < vec.size(); ++i)
....
Dies führt dazu, dass der Compiler die Warnung auslöst, dass vorzeichenbehaftete / vorzeichenlose Variablen gemischt verwendet werden. Wenn ich die Indexvariable als for( size_t i = 0; i < vec.size(); i++ )
(oder an unsigned int
) mache , werden die Probleme behoben.
Wenn es spezifischer wird, Windows-Typen zu verwenden, befassen sich die meisten Windows-APIs mit DWORD (das als lange ohne Vorzeichen definiert wurde).
Wenn ich also eine ähnliche Iteration verwende, wird wieder dieselbe Warnung ausgelöst. Nun, wenn ich es umschreibe als
DWORD dwCount;
....
for(DWORD i = 0; i < dwCount; ++i)
....
Ich finde das ein bisschen komisch. Es könnte das Problem mit den Wahrnehmungen sein.
Ich bin damit einverstanden, dass wir denselben Typ von Indexvariablen verwenden sollen, um zu vermeiden, dass bei den Indexvariablen Bereichsprobleme auftreten können. Zum Beispiel wenn wir verwenden
_int64 i64Count; //
....
for(_int64 i = 0; i < i64Count; ++i)
....
Im Fall von DWORD oder vorzeichenlosen Ganzzahlen gibt es jedoch Probleme beim Umschreiben als
for(int i = 0; (size_t)i < vec.size(); ++i)
Wie die meisten Leute arbeiten mit ähnlichen Themen?
std::size_t
ist ein höherer Rang als int (oder sogar lang). Wenn die Größe des Vektors jemals überschritten wirdstd::numeric_limits<int>::max()
, werden Sie es bereuen, int verwendet zu haben.Antworten:
vector hat ein typedef, das Ihnen den richtigen Typ angibt, der verwendet werden soll: -
Es wird fast immer als size_t definiert, aber darauf können Sie sich nicht verlassen
quelle
auto i = 0
? Das hilft überhaupt nicht,i
ein zu werdenint
.using index_t = std::vector<int>::size_type;
.Verwenden Sie dazu einen Iterator, keine
for
Schleife.Für die anderen sollte, solange der Variablentyp dieselbe Größe hat,
static_cast
einwandfrei funktionieren (dhDWORD
bisint16_t
)quelle
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i)
ist ein Schmerz zu schreiben. Habenfor (auto i = vec.begin();...
ist viel besser lesbar. Natürlichforeach
ist auch in C ++ 11.Der von Ihnen beschriebene Fall ist eines der Dinge, die ich auch in C ++ nicht mag. Aber ich habe gelernt, damit zu leben, entweder indem ich es benutze
for( size_t i = 0; i < vec.size(); i++ )
oder
for( int i = 0; i < (int)vec.size(); i++ )
(Letzteres natürlich nur, wenn kein Risiko eines int-Überlaufs besteht).
quelle
Der Grund, warum Sie vor einem Vergleich zwischen signiert und nicht signiert gewarnt werden, liegt darin, dass der signierte Wert wahrscheinlich in einen nicht signierten Wert konvertiert wird, was möglicherweise nicht Ihren Erwartungen entspricht.
In Ihrem Beispiel (im Vergleich
int
zusize_t
)int
wird implizit in konvertiertsize_t
(es sei denn, es hatint
irgendwie einen größeren Bereich alssize_t
). Wenn dasint
also negativ ist, ist es wahrscheinlich größer als der Wert, mit dem Sie es vergleichen, aufgrund des Umlaufs. Dies ist kein Problem, wenn Ihr Index niemals negativ ist, aber Sie erhalten trotzdem diese Warnung.Verwenden Sie stattdessen einen nicht signierten Typen (wie
unsigned int
,size_t
oder, wie John B empfiehlt ,std::vector<int>::size_type
) für Ihre Indexvariable:Seien Sie jedoch vorsichtig, wenn Sie herunterzählen:
Das obige funktioniert nicht, da
i >= 0
es immer wahr ist, wenni
es nicht signiert ist. Verwenden Sie stattdessen den " Pfeiloperator " für Schleifen, die herunterzählen:Wie andere Antworten zeigen, möchten Sie normalerweise einen Iterator verwenden, um a zu durchlaufen
vector
. Hier ist die C ++ 11-Syntax:quelle
unsigned int
nicht groß genug ist, um die Größe zu halten.Als neue Option für C ++ 11 können Sie folgende Aktionen ausführen
for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}
und
for(decltype(dWord) i = 0; i < dWord; ++i) {...}
Es wiederholt sich zwar etwas mehr als die grundlegende for-Schleife, ist aber bei weitem nicht so langwierig wie die Angabe von Werten vor '11, und die konsequente Verwendung dieses Musters funktioniert für die meisten, wenn nicht alle möglichen Begriffe, die Sie möchten Ich möchte mit vergleichen, was es großartig für Code-Refactoring macht. Es funktioniert sogar für einfache Fälle wie diesen:
int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)
Während Sie
auto
immer dann verwenden sollten, wenn Siei
einen intelligenten Wert (wievec.begin()
)decltype
festlegen , funktioniert dies, wenn Sie eine Konstante wie Null festlegen, wobei auto dies nur auflösen würde,int
da 0 ein einfaches ganzzahliges Literal ist.Um ehrlich zu sein, würde ich gerne einen Compiler-Mechanismus sehen, mit dem die
auto
Typbestimmung für Schleifeninkrementierer erweitert werden kann, um den verglichenen Wert zu betrachten.quelle
Ich benutze eine Besetzung für int, wie in
for (int i = 0; i < (int)v.size(); ++i)
. Ja, es ist hässlich. Ich beschuldige das dumme Design der Standardbibliothek, in der sie beschlossen haben, vorzeichenlose Ganzzahlen zur Darstellung von Größen zu verwenden. (Um .. was? Den Bereich um ein Bit zu erweitern?)quelle
if(v.size()-1 > 0) { ... }
, für einen leeren Container true zurückzugeben? Das Problem ist, dass Größen auch häufig in der Arithmetik verwendet werden, insb. mit indexbasierten Containern, die Probleme verursachen, da sie nicht signiert sind. Grundsätzlich ist die Verwendung von vorzeichenlosen Typen für etwas anderes als 1) bitweise Manipulationen oder 2) modulare Arithmetik problematisch.if(v.size() > 1) { ... }
da dies die Absicht klarer macht und als zusätzlicher Bonus die Ausgabe von signiert / nicht signiert ungültig wird), sehe ich in bestimmten Fällen, wie Signiertheit könnte nützlich sein. Ich stehe korrigiert.