Pour représenter des entiers positifs, la STL utilise des entiers non signés. Par exemple, la fonction std::vector::operator[] prend en paramètre un entier non signé.

Qt, par contre, utilise int. Par exemple, la fonction QVector::operator[] prend en paramètre un int.
Le Google C++ Style Guide s'oppose aussi aux entiers non signés (lire la section "Integer_Types").

La raison invoquée par le Google C++ Style Guide est la suivante :
Consider:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
for (unsigned int i = foo.Length()-1; i >= 0; --i) ...
This code will never terminate! Sometimes gcc will notice this bug and warn you, but often it will not. Equally bad bugs can occur when comparing signed and unsigned variables. Basically, C's type-promotion scheme causes unsigned types to behave differently than one might expect.

So, document that a variable is non-negative using assertions. Don't use an unsigned type.
D'un autre côté, utiliser des entiers non signés permet de réduire le nombre de contrôles quand un entier doit être positif.
Par exemple, voici un code utilisant uniquement des entiers signés :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void f(int integer)
{
    if(integer >= 0) {
        g(integer);
    } else {
        // code A
    }
}
 
void g(int nonNegativeInteger)
{
    assert(nonNegativeInteger >= 0);
    thowIfNegative(nonNegativeInteger);
    // code B
    h(nonNegativeInteger);
    // code C
}
 
void h(int nonNegativeInteger)
{
    assert(nonNegativeInteger >= 0);
    thowIfNegative(nonNegativeInteger);
    // code D
}
Voici le même code utilisant des entiers non signés pour les entiers toujours positifs :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void f(int integer)
{
    if(integer >= 0) {
        const size_t castedInteger = checkedConvert<size_t>(integer);
            // check if integer >= 0
            // thow exception if integer > SIZE_MAX
        g(castedInteger);
    } else {
        // code A
    }
}
 
void g(size_t integer)
{
    // code B
    h(integer);
    // code C
}
 
void h(size_t integer)
{
    // code D
}
D'ailleurs, pour ceux que ça intéresse, voici mon code de checkedConvert :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Version de g++ : 6.1.0
 
#include <cassert>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <typeinfo>
#include <type_traits>
 
/*!
 * \brief     Convert signed integer to another signed integer type.
 * \exception std::overflow_error  param is too big   to be convertible to ResultT.
 * \exception std::underflow_error param is too small to be convertible to ResultT.
 */
template<class ResultT, class ParamT,
    typename std::enable_if<
        std::is_integral<ResultT>::value &&
        std::is_integral<ParamT >::value &&
        std::is_signed  <ResultT>::value &&
        std::is_signed  <ParamT >::value
    >::type* = nullptr
>
ResultT checkedConvert(ParamT param)
{
 #ifndef DO_NOT_CHECK_INTEGER_LIMITS_ON_CONVERSION
    if(param > std::numeric_limits<ResultT>::max()) {
        std::ostringstream streamMessage;
        streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                      << " to "                     << typeid(ResultT).name() << ": "
                      << param << " is too big (maximal allowed value: "
                      << std::numeric_limits<ResultT>::max() << ").";
        throw std::overflow_error(streamMessage.str());
    } else if(param < std::numeric_limits<ResultT>::min()) {
        std::ostringstream streamMessage;
        streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                      << " to "                     << typeid(ResultT).name() << ": "
                      << param << " is too small (minimal allowed value: "
                      << std::numeric_limits<ResultT>::min() << ").";
        throw std::underflow_error(streamMessage.str());
    }
 #endif
    return param;
}
 
/*!
 * \brief     Convert nonnegative signed integer to unsigned integer type.
 * \pre       param >= 0
 * \exception std::overflow_error param is too big to be convertible to ResultT.
 * \exception std::domain_error   (in Release mode) param < 0
 */
template<class ResultT, class ParamT,
    typename std::enable_if<
        std::is_integral<ResultT>::value &&
        std::is_integral<ParamT >::value &&
        !std::is_signed <ResultT>::value &&
         std::is_signed <ParamT >::value
    >::type* = nullptr
>
ResultT checkedConvert(ParamT param)
{
    assert(param >= 0);
    if(param < 0) {
        std::ostringstream streamMessage;
        streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                      << " to "                     << typeid(ResultT).name() << ": "
                      << param << " is negative.";
        throw std::domain_error(streamMessage.str());
    }
 #ifndef DO_NOT_CHECK_INTEGER_LIMITS_ON_CONVERSION
  #pragma GCC diagnostic push
  #pragma GCC diagnostic ignored "-Wsign-compare"
    if(param > std::numeric_limits<ResultT>::max()) {
        std::ostringstream streamMessage;
        streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                      << " to "                     << typeid(ResultT).name() << ": "
                      << param << " is too big (maximal allowed value:"
                      << std::numeric_limits<ResultT>::max() << ").";
        throw std::overflow_error(streamMessage.str());
    }
  #pragma GCC diagnostic pop
 #endif
    return param;
}
 
/*!
 * \brief     Convert unsigned integer to another integer type.
 * \exception std::overflow_error param is too big to be convertible to ResultT.
 */
template<class ResultT, class ParamT,
    typename std::enable_if<
        std::is_integral<ResultT>::value &&
        std::is_integral<ParamT >::value &&
        !std::is_signed <ParamT >::value
    >::type* = nullptr
>
ResultT checkedConvert(ParamT param)
{
 #ifndef DO_NOT_CHECK_INTEGER_LIMITS_ON_CONVERSION
  #pragma GCC diagnostic push
  #pragma GCC diagnostic ignored "-Wsign-compare"
    if(param > std::numeric_limits<ResultT>::max()) {
        std::ostringstream streamMessage;
        streamMessage << "Failure to convert from " << typeid(ParamT).name()
                      << " to " << typeid(ResultT).name() << ": "
                      << param << " is too big (maximal allowed value:"
                      << std::numeric_limits<ResultT>::max() << ").";
        throw std::overflow_error(streamMessage.str());
    }
  #pragma GCC diagnostic pop
 #endif
    return param;
}
PS : Rappels :
  • En français, "positif" signifie "positif ou nul" et "négatif" signifie "négatif ou nul".
  • En anglais, "positive" signifie "strictement positif" et "negative" signifie "strictement négatif".


EDIT 09/10/2016 vers 19h24 : std::runtime_error remplacé par std::range_error et std::logic_error remplacé par std::domain_error.
EDIT 09/10/2016 vers 19h32 : std::range_error remplacé par std::overflow_error et std::underflow_error.