You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _articles/c++_std_size_t.md
+56-14Lines changed: 56 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,7 @@ for (unsigned int i = 0; i < largeVector.size(); ++i) { ... }
30
30
31
31
## Héritage du C: ``size_t``
32
32
33
-
Avant le C++, le **langage C** a introduit [**``size_t``**](https://en.cppreference.com/w/c/types/size_t.html) (via [``<stddef.h>``](https://en.cppreference.com/w/c/header/stddef.html)) comme **type standard pour toute manipulation de tailles mémoire**. Le standard **POSIX** (fondé sur le C) l'a ensuite intégré et intégré dans ses propres interfaces, notamment via le header système [``<sys/types.h>``](https://man7.org/linux/man-pages/man3/size_t.3type.html).
33
+
Avant le C++, le **langage C** a introduit [**``size_t``**](https://en.cppreference.com/w/c/types/size_t.html) (via [``<stddef.h>``](https://en.cppreference.com/w/c/header/stddef.html)) comme **type standard pour toute manipulation de tailles mémoire**. Le standard **POSIX** (fondé sur le C) l'utilise dans ses propres interfaces, notamment via le header système [``<sys/types.h>``](https://man7.org/linux/man-pages/man3/size_t.3type.html).
34
34
35
35
Il est omniprésent dans la bibliothèque standard C:
@@ -175,12 +175,12 @@ for (std::size_t i = v.size() - 1; i >= 0; --i) { ... }
175
175
176
176
Le type [**``ssize_t``**](https://man7.org/linux/man-pages/man3/size_t.3type.html) est un type historique des systèmes **POSIX** (Linux/Unix). Il est couramment utilisé dans les fonctions système (comme [``read``](https://man7.org/linux/man-pages/man2/read.2.html) ou [``write``](https://man7.org/linux/man-pages/man2/write.2.html)) pour retourner soit une taille, soit une erreur (via une valeur négative).
| type | type réel | Portabilité | Usage sémantique |
260
+
| :--- | :---: | :--- | :--- |
261
+
|**``std::size_t``**|*implementation-defined*| oui (standard ISO C++)|**Indexes**, **quantités** et **tailles** d'objets dans un conteneur ou tableau|
262
+
|**``std::ptrdiff_t``**|*implementation-defined*| oui (standard ISO C++)|**Différences** entre **deux pointeurs**|
263
263
264
264
Sa largeur est garantie de faire au moins **17 bits** ([The bit width of std::ptrdiff_t is not less than 17. (since C++11)](https://en.cppreference.com/w/cpp/types/ptrdiff_t.html))
265
265
266
266
> Concernant les **plages de valeurs** de ``std::size_t`` et ``std::ptrdiff_t``, le standard C++ donne les mêmes garanties que le standard C.<br>
267
267
> ``std::size_t`` n'est **pas formellement compris** dans ``std::ptrdiff_t``, mais ce n'est **pas un problème** pour autant. Nous en avons parlé [**ici**](#limitation-de-la-plage-de-valeurs).
268
268
269
+
### ``std::uintptr_t`` et ``std::intptr_t``
270
+
271
+
Bien que ``std::size_t`` soit souvent utilisé pour des **offset mémoire** au sein d'un même objet (comme avec la macro [``offsetof``](https://en.cppreference.com/w/cpp/types/offsetof.html) qui donne un ``std::size_t``), il n'est pas destiné à faire des calculs d'adresses complexes. Pour convertir un pointeur en entier afin d'effectuer de l'arithmétique bas niveau (masquage de bits, calcul d'alignement, etc), préférez [**``std::uintptr_t``**](https://en.cppreference.com/w/cpp/types/integer.html) ou [**``std::intptr_t``**](https://en.cppreference.com/w/cpp/types/integer.html), qui est garanti d'être assez large pour contenir un pointeur.
272
+
273
+
| type | type réel | Portabilité | Usage sémantique |
274
+
| :--- | :---: | :--- | :--- |
275
+
|**``std::size_t``**|*implementation-defined*| oui (standard ISO C++) |**Indexes**, **quantités** et **tailles** d'objets dans un conteneur ou tableau |
276
+
|**``std::ptrdiff_t``**|*implementation-defined*| oui (standard ISO C++) |**Différences** entre **deux pointeurs**|
277
+
|**``std::uintptr_t``**|*implementation-defined*| oui (standard ISO C++) |**Arithmétique sur pointeurs**|
278
+
|**``std::intptr_t``**|*implementation-defined*| oui (standard ISO C++) |**Arithmétique** sur pointeurs avec valeurs **négatives**|
279
+
269
280
## Dans la STL (Standard Template Library)
270
281
271
282
Les conteneurs de la STL (``vector``, ``list``, ``string``, etc) définissent des **alias internes** pour **garantir la généricité** du code.
272
283
273
284
Ils sont **visibles en public** dans les classes, et dans presque toutes les **signatures de fonctions** membres:
274
285
275
-
-**``T::size_type``**: Type non signé pour représenter le **nombre d'éléments stockés**. C'est notamment le type de retour de la méthode [**``std::vector<T>::size()``**](https://en.cppreference.com/w/cpp/container/vector/size) et le type attendu par l'opérateur [**``std::vector<T>::operator[]``**](https://en.cppreference.com/w/cpp/container/vector/operator_at).
286
+
-**``T::size_type``**: Type non signé pour représenter le **nombre d'éléments stockés**. C'est notamment le type de retour de la méthode [**``std::vector<T>::size()``**](https://en.cppreference.com/w/cpp/container/vector/size) et le type attendu par l'opérateur [**``std::vector<T>::operator[]``**](https://en.cppreference.com/w/cpp/container/vector/operator_at). Ce type est très souvent ``std::size_t`` par défaut.
276
287
277
-
-**``T::difference_type``**: Type signé pour les distances. C'est le type retourné par l'opérateur de **soustraction entre deux itérateurs** (``it2 - it1``) ou par la fonction [**``std::distance``**](https://en.cppreference.com/w/cpp/iterator/distance).
288
+
-**``T::difference_type``**: Type signé pour les distances. C'est le type retourné par l'opérateur de **soustraction entre deux itérateurs** (``it2 - it1``) ou par la fonction [**``std::distance``**](https://en.cppreference.com/w/cpp/iterator/distance). Ce type est très souvent ``std::ptrdiff_t`` par défaut.
278
289
279
290
{% highlight cpp %}
280
291
std::vector<int> numbers = {10, 20, 30};
@@ -301,6 +312,37 @@ auto distance = numbers.end() - numbers.begin();
301
312
302
313
Il prend le type retourné par les fonctions, [**sans risque de conversion maladroite**](#auto-complique-la-lecture-du-code).
303
314
315
+
### Valeur sentinelle de ``std::string``
316
+
317
+
318
+
La fonction [``std::string::find``](https://en.cppreference.com/w/cpp/string/basic_string/find.html) retourne une valeur de type ``std::string::size_type``. Cet alias correspond à ``std::allocator_traits<Allocator>::size_type``, dont le type réel est **systématiquement [``std::size_t``](https://en.cppreference.com/w/cpp/memory/allocator.html)** pour [l'allocateur par défaut](https://en.cppreference.com/w/cpp/memory/allocator.html).
319
+
320
+
> Pour être exact, ``std::string`` est un alias de la classe template [``std::basic_string<CharT, Traits, Allocator>``](https://en.cppreference.com/w/cpp/string/basic_string.html). Cette précision est utile car les types que nous allons manipuler en dépendent.
321
+
322
+
Cette fonction [``std::string::find``](https://en.cppreference.com/w/cpp/string/basic_string/find.html) retourne la **position de l'élément trouvé**:
323
+
324
+
{% highlight cpp %}
325
+
auto string = std::string{"Hello World!"};
326
+
std::size_t position = string.find("World"); // position vaut 5
327
+
{% endhighlight %}
328
+
329
+
La STL propose une **valeur sentinelle** pour indiquer que **la chaîne recherchée n'a pas été trouvée**:
330
+
{% highlight cpp linenos highlight_lines="4" %}
331
+
auto string = std::string{"Hello World!"};
332
+
std::size_t position = string.find("Word"); // position vaut std::string::npos
333
+
334
+
if (position == std::string::npos)
335
+
{
336
+
std::println("Chaîne non trouvée");
337
+
}
338
+
{% endhighlight %}
339
+
340
+
[**``std::string::npos``**](https://en.cppreference.com/w/cpp/string/basic_string/npos) est une constante de type **``std::size_t``**. Cette **valeur sentinelle** vaut **``-1``**.
341
+
342
+
``-1`` dans un type non-signé ? C'est parfaitement légal: [dans l'**arithmétique non signée**, les **overflow/underflow** ont la **garantie de boucler**](#le-mélange-signé--non-signé). ``-1`` devient donc **la plus grande valeur possible** de ``std::size_t`` (qu'on ne peut pas formellement citer car le standard [ne garantit pas de largeur exacte pour ce type](#dépendance-à-labi-et-au-modèle-de-données)).
343
+
344
+
Ce mécanisme, parfois source de bugs, est utilisé ici pour **garantir une valeur sentinelle impossible à atteindre** pour une taille réelle de chaîne.
345
+
304
346
## Literals (Depuis C++23)
305
347
306
348
Le C++23 introduit des [**literals**](/articles/c++/literals#size-literal-c23) pour manipuler ces types sans conversion implicite:
@@ -532,7 +574,7 @@ Les [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuid
532
574
533
575
### Ne mélangez pas signé et non signé (ES.100)
534
576
535
-
Le principe est simple: [**Don't mix signed and unsigned arithmetic**](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#res-mix). Le mélange provoque des **conversions silencieuses** et des bugs difficiles à tracer. Nous l'avons illustré avec les [frictions de Qt](#les-comparaisons-mixtes).
577
+
Le principe est simple: Ne mélangez pas l'arithmétique signée et non-signée ([**Don't mix signed and unsigned arithmetic**](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#res-mix)). Le mélange provoque des **conversions silencieuses** et des bugs difficiles à tracer. Nous l'avons illustré avec les [frictions de Qt](#les-comparaisons-mixtes).
0 commit comments