117 votes

Qui en-tête dois-je inclure pour " size_t`?

Selon cppreference.com size_t est définie de plusieurs en-têtes, à savoir

<cstddef>
<cstdio>
<cstring>
<ctime>

Et, depuis C++11, également dans

<cstdlib>
<cwchar> 

Tout d'abord je me demande pourquoi c'est le cas. N'est-ce pas en contradiction avec le SÈCHE principe? Cependant, ma question est:

Qui de l'un de ces en-têtes dois-je inclure pour utiliser size_t? Importe-t-il à tous?

110voto

Sean Points 22088

En supposant que je voulais minimiser les fonctions et les types I importait, j'irais avec cstddef comme il ne veut pas déclarer toutes les fonctions et ne déclare qu'6 types. Les autres se concentrent sur des domaines particuliers (chaînes de caractères, le temps, IO) qui ne peut pas d'importance pour vous.

Notez que cstddef seulement des garanties à définir std::size_t, qui est, en définissant size_t en l'espace de noms std, même si elle peut fournir ce nom dans l'espace de noms global (en fait, plain size_t).

En revanche, stddef.h (qui est également un en-tête disponible en C) des garanties pour définir size_t en l'espace de noms global, et peut également fournir de l' std::size_t.

51voto

Pixelchemist Points 3636

En fait, le synopsis (inclus dans la norme C++) de plusieurs en-têtes specifially comprennent size_t ainsi que d'autres en-têtes de définir le type size_t (basé sur la norme C comme l' <cX> - têtes sont juste ISO C <X.h> - têtes avec a noté des changements où la suppression de size_t n'est pas indiqué).

La norme C++ , cependant, se réfère <cstddef> pour la définition de l' std::size_t

  • dans 18.2 Types,
  • dans 5.3.3 Sizeof,
  • dans 3.7.4.2 de Libération de la mémoire de fonctions (qui se réfère à 18,2) et
  • dans 3.7.4.1 fonctions d'Allocation (se réfère également à 18,2).

Par conséquent, et en raison du fait qu' <cstddef> seulement introduit les types et les fonctions, je collerais à cet en-tête pour faire std::size_t disponible.


De noter quelques petites choses :

  1. Le type d' std::size_t est obtenue à l'aide d' decltype sans inclure un en-tête

    Si vous avez l'intention d'introduire une définition de type dans votre code, de toute façon (c'est à dire parce que vous écrivez un récipient et souhaitez proposer un size_type typedef), vous pouvez utiliser le global sizeof, sizeof... ou alignof opérateurs pour définir votre type sans y inclure les en-têtes à tous, depuis ces opérateurs retour std::size_t par définition standard et vous pouvez utiliser decltype sur les:

    using size_type = decltype(alignof(char));
    
  2. std::size_t n'est pas en soi visible au niveau mondial, bien que les fonctions avec std::size_t arguments.

    La déclarées implicitement global allocation et de désallocation de fonctions

    void* operator new(std::size_t);
    void* operator new[](std::size_t);
    void operator delete(void*);
    void operator delete[](void*);
    

    ne PAS introduire size_t, std ou std::size_t et

    se référant à l' std ou std::size_t est mal formé, à moins que le nom a été déclarée en incluant l'en-tête approprié.

  3. L'utilisateur ne peut pas redéfinir std::size_t bien qu'il est possible d'avoir plusieurs typedefs référence au même type dans le même espace de noms.

    Bien que, l'apparition de multiples définitions de l' size_t dans std est parfaitement valide que par 7.1.3 / 3, il n'est pas autorisé à ajouter des déclarations d' namespace std comme par 17.6.4.2.1 / 1:

    Le comportement d'un programme C++ n'est pas définie si on ajoute les déclarations ou les définitions de l'espace de noms std ou à un espace de noms à l'intérieur de l'espace de noms std, sauf indication contraire.

    L'ajout d'un bon typedef pour size_t de l'espace de noms ne viole pas 7.1.3 mais il ne viole 17.6.4.2.1 et conduit à un comportement indéterminé.

    Précisions: Essayez de ne pas mal interpréter 7.1.3 et n'ajoutez pas de déclarations ou de définitions std (à l'exception de quelques le modèle de la spécialisation des cas où un typedef n'est pas un modèle de spécialisation). L'extension de l' namespace std

8voto

Ville-Valtteri Points 3536

Tous les standards de la bibliothèque de fichiers d'en-tête ont la même définition; il n'est pas question que l'un de vous inclure dans votre propre code. Sur mon ordinateur, j'ai la déclaration suivante en _stddef.h. Ce fichier est inclus par tous les fichiers que vous avez énumérés.

/*
   Define the size_t type in the std namespace if in C++ or globally if in C.
   If we're in C++, make the _SIZE_T macro expand to std::size_t
*/

#if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
#  define _SIZE_T_DEFINED
#if defined(_WIN64)
   typedef unsigned __int64 size_t;
#else
   typedef unsigned int size_t;
#endif
#  if defined(__cplusplus)
#    define _SIZE_T std::size_t
#  else
#    define _SIZE_T size_t
#  endif
#endif

7voto

Maxim Yegorushkin Points 29380

Vous pourriez le faire sans en-tête:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

C'est parce que la norme C++ nécessite:

Le résultat de l' sizeof et sizeof... est une constante de type std::size_t. [ Note: std::size_t est défini dans la norme en-tête <cstddef> (18.2). - la note de fin ]

En d'autres termes, la norme exige que:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");

Notez également qu'il est parfaitement bien de faire ce typedef déclaration dans le mondial et dans std d'espace de noms, tant qu'il correspond à tous les autres typedef des déclarations de la même définition de type-nom (une erreur du compilateur est délivrée sur la non-correspondance des déclarations).

C'est parce que:

  • §7.1.3.1 Une définition de type nom- ne pas introduire un nouveau type de la façon dont une déclaration de classe (9.1) ou déclaration d'enum.

  • §7.1.3.3 Dans un non-étendue de classe, un typedef spécificateur peut être utilisé pour redéfinir le nom de n'importe quel type déclaré dans le champ d'application pour désigner le type à qui il fait déjà référence.


Pour les sceptiques disent que cela constitue un ajout d'un nouveau type dans l'espace de noms std, et un tel acte est explicitement interdite par la norme, et c'est UB et c'est tous là pour ça; je dois dire que cette attitude élève à ignorer et nier meilleure compréhension des enjeux sous-jacents.

La norme des interdictions de l'ajout de nouvelles déclarations et les définitions dans l'espace de noms std car en faisant de sorte que l'utilisateur peut faire un désordre de la bibliothèque standard et tirer sur sa jambe large. Pour les rédacteurs de normes, il était plus facile pour permettre à l'utilisateur de se spécialiser un peu de choses et l'interdiction de faire quoi que ce soit, pour faire bonne mesure, plutôt que d'interdire tous les seule chose que l'utilisateur ne doit pas faire au risque de manquer quelque chose d'important (et que la jambe). Ils l'ont fait dans le passé, lorsque exigeant qu'aucun conteneur standard doit être instancié avec un type incomplète, alors qu'en fait, certains conteneurs pourraient bien faire (voir Le Standard Bibliothécaire: les Conteneurs sont Incomplètes Types de Matthew H. Austern):

... En fin de compte, tout cela semblait trop sombres et trop mal compris; le comité de normalisation ne pense pas qu'il y avait un quelconque choix, sauf pour dire que les conteneurs STL ne sont pas censés travailler avec incomplètes types. Pour faire bonne mesure, nous avons appliqué cette interdiction pour le reste de la bibliothèque standard.

... De recul, maintenant que la technologie est mieux comprise, cette décision semble encore raison sur le fond. Oui, dans certains cas, il est possible de mettre en œuvre certaines des conteneurs standard afin qu'ils puissent être instancié avec incomplètes types - mais il est également clair que, dans d'autres cas, il serait difficile ou impossible. C'était surtout la chance que le premier test, nous avons essayé, à l'aide de std::vector, qui est arrivé à être l'un des cas faciles.

Étant donné que la langue règles exigent std::size_t exactement l' decltype(sizeof(int)), faisant namespace std { using size_t = decltype(sizeof(int)); } est une de ces choses qui ne cassent pas quoi que ce soit.

Avant C++11 il n'y avait pas decltype , et donc aucun moyen de déclarer le type d' sizeof suite à une simple déclaration, sans faire une bonne affaire de modèles impliqués. size_t des alias de types différents sur différentes architectures cibles, cependant, il ne serait pas une solution élégante pour ajouter un nouveau type juste pour le résultat de l' sizeof, et il n'existe pas de standard intégré dans les typedefs. Par conséquent, la solution la plus compacte à l'époque était de mettre size_t type d'alias dans un en-tête spécifique et document.

En C++11, il est maintenant une façon d'écrire que l'exigence exacte de la norme comme un simple déclaration.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X