<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Shreyash Rai — #gotchas</title><description>Everything tagged “gotchas”.</description><link>https://shreyashrai.com</link><item><title>size_t is unsigned, so counting down past zero wraps around</title><link>https://shreyashrai.com/til/cpp-size-t-underflow</link><guid isPermaLink="true">https://shreyashrai.com/til/cpp-size-t-underflow</guid><pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I had a loop that walked a vector backwards and it never terminated. The bug is
that &lt;code&gt;size_t&lt;/code&gt; is &lt;strong&gt;unsigned&lt;/strong&gt;, so it can never be negative — subtracting past
zero wraps to a huge positive number instead.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Broken: when i == 0, --i wraps to SIZE_MAX, so i &amp;gt;= 0 is always true.
for (size_t i = v.size() - 1; i &amp;gt;= 0; --i) {
    use(v[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same trap hides in any &lt;code&gt;v.size() - 1&lt;/code&gt; when the vector is empty: &lt;code&gt;0u - 1&lt;/code&gt;
is &lt;code&gt;SIZE_MAX&lt;/code&gt;, not &lt;code&gt;-1&lt;/code&gt;, so a &quot;last index&quot; computed that way points way off the
end.&lt;/p&gt;
&lt;p&gt;One fix is to offset the index by one and count the &lt;em&gt;other&lt;/em&gt; variable down, so
the loop variable stays in valid unsigned territory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Fixed: i is the count remaining; the real index is i - 1.
for (size_t i = v.size(); i &amp;gt; 0; --i) {
    use(v[i - 1]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The general rule: if a value can go negative, don&apos;t store it in an unsigned
type. Reach for a signed index (or C++20&apos;s &lt;code&gt;std::ssize&lt;/code&gt;) when you need to count
below zero.&lt;/p&gt;
</content:encoded><category>c++</category><category>gotchas</category></item></channel></rss>