Какой заголовок я должен включить для '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_type
typedef) вы можете использовать глобальный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 теперь есть способ записать это точное требование Стандарта как одно простое объявление.