Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>As a rule, in C and C++ you should never use an unsigned type such as <code>size_t</code> to restrict the domain. That's because (1) these languages provide no range checking, and (2) they do provide unreasonable implicit promotions. No range checking means (1) no advantage, and unreasonable implicit promotions means (2) very undesirable disadvantages, so it's plain stupid thing to do: no advantage, very undesirable disadvantages.</p> <p>However, the standard libraries for these languages do that. They do it for <em>historical reasons</em> only, caught irreversibly in early decisions which at one time made sense. This has both extremely silly consequences such as C99 requiring 17 (!) bits for <code>ptrdiff_t</code>, and it has the aforementioned extremely undesirable consequences such as using inordinately much time on hunting down bugs resulting from implicit promotions (etc.). For example, in C++ you are practically guaranteed that <code>std::string( "bah!" ).length() &lt; -5</code> &ndash; which can easily trip you up and anyway is as silly as it is possible to design.</p> <p>Now, you can't infuse new member functions in <code>std::vector</code>, but you can add a freestanding function. A good name is <code>countOf</code>. Template it so that it can be applied to just about anything (raw arrays, vectors, etc.).</p> <p>The triad of functions <code>startOf</code>, <code>endOf</code> and <code>countOf</code> were, as far as I know, first identified by Dietmar Kuehl. C++0x will have <code>std::begin</code> and <code>std::end</code>, but AFAIK no corresponding <code>std::size</code>. In the meantime you can just define this support, which allows you to treat any kinds of container plus raw arrays the same.</p> <p>An example implementation &amp; further discussion is provided at <a href="http://alfps.wordpress.com/2010/05/10/how-to-avoid-disastrous-integer-wrap-around/" rel="nofollow">my blog</a>.</p> <hr/> <p><strong>EDIT</strong> Adding some code, because it's requested in the comments.</p> <p>Detection of suitable iterator type:</p> <pre><code>template&lt; typename Type &gt; struct It { typedef typename Type::iterator T; }; template&lt; typename Type &gt; struct It&lt; Type const &gt; { typedef typename Type::const_iterator T; }; template&lt; typename ElemType, Size N &gt; struct It&lt; ElemType[N] &gt; { typedef ElemType* T; }; </code></pre> <p>And the <code>countOf</code>, <code>startOf</code> and <code>endOf</code> functions, using that deduced iterator type:</p> <pre><code>template&lt; typename T &gt; inline Size countOf( T const&amp; c ) { return static_cast&lt;Size&gt;( c.size() ); } template&lt; typename T, Size N &gt; inline Size countOf( T (&amp;)[N] ) { return N; } template&lt; typename T &gt; inline typename It&lt;T&gt;::T startOf( T&amp; c ) { return c.begin(); } template&lt; typename T, Size N &gt; inline T* startOf( T (&amp;a)[N] ) { return a; } template&lt; typename T &gt; inline typename It&lt;T&gt;::T endOf( T&amp; c ) { return c.end(); } template&lt; typename T, Size N &gt; inline T* endOf( T (&amp;a)[N] ) { return a + N; } </code></pre> <p>where <code>Size</code> is a typedef for <code>ptrdiff_t</code>.</p> <p>Note: in 64-bit Windows <code>int</code> (and even <code>long</code>) is 32-bit. Hence, <code>int</code> is in general not sufficient for a really large array. <code>ptrdiff_t</code> is guaranteed to be able to represent the difference between any two pointers, when that difference is well-defined.</p> <hr> <p>Cheers &amp; hth.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. CO"early decisions which at one time made sense" - did they ever make sense? If there were no comparison operators (and possibly you'd need there to be no mixed arithmetic either, just explicit conversion) between signed and unsigned types, then I could sort of see the point of using unsigned types in the standard libraries. As things stand, though, you can't use only signed types, you can't use only unsigned types, and you can't safely mix them. Which as you say is a bit of a bind.
      singulars
    2. COI think it's important that your types respect the fundamental properties of what they represent. It makes perfect sense, for example, to talk about the difference between two sizes, and the standard formula for that difference is `abs(size1, size2)`. If this doesn't work for the type you're using for sizes, then you're using the wrong type.
      singulars
    3. CO@James: but conversely, if the type you're using for indexes doesn't let you talk about a *signed* difference, then you're using the wrong type. So you can't use the same fixed-width type for both sizes and indexes, and you can't use a pair of corresponding signed/unsigned types because they don't fit, you can't have the signed one express signed differences in range of the unsigned one *and* the unsigned one express absolute differences in range of the signed one. Introduce a bigint builtin type to C and C++ and we could have sensible arithmetic, but we'd lose that close-to-the-metal vibe.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload