Какой заголовок я должен включить для 'size t'?
согласно cppreference.com size_t определяется в нескольких заголовках, а именно
<cstddef>
<cstdio>
<cstring>
<ctime>
и, начиная с C++11, также в
<cstdlib>
<cwchar>
прежде всего мне интересно, почему это так. Разве это не противоречит сухой принципе? Однако, мой вопрос:
какой из этих заголовков я должен включить, чтобы использовать size_t? Это вообще имеет значение?
4 ответа:
предполагая, что я хотел минимизировать функции и типы, которые я импортировал, я бы пошел с
cstddefпоскольку он не объявляет никаких функций и объявляет только 6 типов. Другие сосредоточены на определенных доменах (строки, время, IO), которые могут не иметь значения для вас.отметим, что
cstddefтолько гарантии для определенияstd::size_t, то есть по определениюsize_tв пространстве именstd, хотя мая укажите это имя также в глобальном пространстве имен (фактически, простойsize_t).в противоположность
stddef.h(который также является заголовком, доступным в C) гарантирует определениеsize_tв глобальном пространстве имен, и мая предоставляемstd::size_t.
фактически синопсис (включенный в стандарт C++) нескольких заголовков конкретно включает
size_tа также дальнейшие заголовки определяют типsize_t(на основе стандарта C как<cX>заголовки просто ISO C<X.h>заголовки с отмеченными изменениями, где удалениеsize_tНе указано).стандарт C++, относится к
<cstddef>определениеstd::size_t
- на 18.2 Типы,
- на 5.3.3 Sizeof,
- на 3.7.4.2 функции освобождения (соответствует 18.2) и
- на 3.7.4.1 функции распределения (также относится к 18.2).
поэтому и из-за того, что
<cstddef>только вводит типы и никаких функций, я бы придерживался этого заголовка, чтобы сделатьstd::size_tдоступен.
обратите внимание на несколько моментов :
тип
std::size_tможно получить с помощьюdecltypeбез заголовкаесли вы все равно планируете ввести typedef в свой код (т. е. потому, что вы пишете контейнер и хотите предоставить
size_typetypedef) вы можете использовать глобальныйsizeof,sizeof...илиalignofоператоры для определения вашего типа без включения каких-либо заголовков вообще, так как операторы theose возвращаютstd::size_tв стандартное определение и вы можно использоватьdecltypeна них:using size_type = decltype(alignof(char));
std::size_tне является per se глобально видимым, хотя функции сstd::size_tаргументы.неявно объявленные глобальные функции распределения и освобождения
void* operator new(std::size_t); void* operator new[](std::size_t); void operator delete(void*); void operator delete[](void*);не вводим
size_t,stdилиstd::size_tисо ссылкой на
stdилиstd::size_tплохо сформировано, если имя не было объявлено путем включения соответствующего заголовок.пользователь не может переопределить
std::size_tхотя можно иметь несколько typedefs, ссылающихся на один и тот же тип в одном пространстве имен.хотя, появление нескольких определений
size_tвнутриstdсовершенно действителен согласно 7.1.3 / 3, не разрешается добавлять какие-либо объявления вnamespace stdпо состоянию на 17.6.4.2.1 / 1:в поведение программы на C++ не определено, если она добавляет объявления или определения в пространство имен std или в пространство имен в пространстве имен std, если не указано иное.
добавление правильного typedef для
size_tчтобы пространство имен не нарушало 7.1.3 но это не нарушает 17.6.4.2.1 и приводит к неопределенному поведению.уточнение: постарайтесь не истолковать неправильно 7.1.3 и не добавляйте объявления или определения к
std(за исключением нескольких случаев специализации шаблона, когда typedef не является специализацией шаблона). расширенияnamespace std
все заголовочные файлы стандартной библиотеки имеют одинаковое определение; не имеет значения, какой из них вы включаете в свой собственный код. На моем компьютере у меня есть следующее объявление в
_stddef.h. Этот файл включен в каждый файл, который вы указали./* 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
вы могли бы обойтись без заголовка:
using size_t = decltype(sizeof(int)); using size_t = decltype(sizeof 1); // The shortest is my favourite. using size_t = decltype(sizeof "anything");это потому, что стандарт C++ требует:
результат
sizeofиsizeof...является константой типаstd::size_t. [ Примечание:std::size_tопределен в стандартном заголовочном файле<cstddef>(18.2). - конец Примечание ]другими словами, стандарт требует:
static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value, "This never fails.");
Также обратите внимание, что это прекрасно, чтобы сделать это
typedefдекларация в глобальном и вstdпространство имен, пока оно соответствует всем другимtypedefобъявления же typedef-name (ошибка компилятора выдается при несоответствии объявлений).это потому, что:
§7.1.3.1 в typedef-name не вводит новый тип, как это делает объявление класса (9.1) или объявление перечисления.
§7.1.3.3 в данной неклассовой области a
typedefспецификатор может использоваться для переопределите имя любого типа, объявленного в этой области, чтобы ссылаться на тип, к которому он уже относится.
скептикам, говорящим, что это представляет собой добавление нового типа в пространство имен
std, и такой акт явно запрещен стандартом, и это UB, и это все; я должен сказать, что это отношение сводится к игнорированию и отрицанию более глубокого понимания основополагающих вопросов.добавление стандартных запретов новые объявления и определения в пространстве имен
stdпотому что при этом пользователь может сделать беспорядок стандартной библиотеки и стрелять всю ногу. Для стандартных авторов было проще позволить пользователю специализироваться на нескольких конкретных вещах и запретить делать что-либо еще для хорошей меры, а не запрещать каждую вещь, которую пользователь не должен делать, и рисковать пропустить что-то важное (и эту ногу). Они делали это в прошлом, когда требовали, чтобы ни один стандартный контейнер не был создан с неполным типом, хотя на самом деле некоторые контейнеры вполне могли бы сделать (см. стандартный библиотекарь: контейнеры неполных типов Мэтью Х. Остерн):... В конце концов, все это казалось слишком мутным и слишком плохо понимаемым; комитет по стандартизации не думал, что есть какой-либо выбор, кроме как сказать, что контейнеры STL не должны работать с неполными типами. Для хорошей меры мы применили этот запрет к остальной части стандартной библиотеки тоже.
... Оглядываясь назад, теперь, когда технология лучше понята, это решение все еще кажется в основном правильным. Да, в некоторых случаях можно реализовать некоторые стандартные контейнеры, чтобы они могли быть созданы с неполными типами, но также ясно, что в других случаях это будет сложно или невозможно. Это был в основном шанс, что первый тест мы попробовали, используя
std::vector, случилось быть одним из легких случаев.учитывая, что языковые правила требуют
std::size_tровноdecltype(sizeof(int)), занималсяnamespace std { using size_t = decltype(sizeof(int)); }это одна из тех вещей, которые ничего не сломать.до C++11 не было
decltypeи таким образом нет способа объявить типsizeofрезультат в одном простом заявлении, не получая много шаблонов участвуют.size_tпсевдонимы разных типов на разных целевых архитектурах, однако, было бы не элегантным решением добавить новый встроенный тип только для результатаsizeofи есть никаких стандартных встроенных типов. Следовательно, самым портативным решением в то время было поставитьsize_tвведите псевдоним в какой-то конкретный заголовок и документ.в C++11 теперь есть способ записать это точное требование Стандарта как одно простое объявление.