Какой заголовок следует включить для 'size t'?
по данным cppreference.com size_t
определяется в нескольких заголовках, а именно
<cstddef>
<cstdio>
<cstring>
<ctime>
и, начиная с C++11, также в
<cstdlib>
<cwchar>
прежде всего, мне интересно, почему это так. Разве это не противоречит сухой принципе? Однако мой вопрос:
какой из вышеперечисленных заголовков я должен включить для использования size_t
? Вообще разница?
4 ответов
предполагая, что я хотел минимизировать функции и типы, которые я импортировал, я бы пошел с cstddef
поскольку он не объявляет никаких функций и объявляет только 6 типов. Другие сосредоточены на определенных доменах (strings, time, 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
не является как таковой глобально видимым, хотя функции с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))
, doing namespace std { using size_t = decltype(sizeof(int)); }
это одна из тех вещей, которые ничего не сломать.
до C++11 не было decltype
и, таким образом, нет способа объявить тип sizeof
результат в одном простом заявлении, не получая много шаблонов, участвующих. size_t
псевдонимы разных типов на разных целевых архитектурах, однако, это не было бы элегантным решением добавить новый встроенный тип только для результата sizeof
и есть никаких стандартных встроенных типов. Следовательно, самым портативным решением в то время было поставить size_t
введите псевдоним в определенный заголовок и документ.
в C++11 теперь есть способ записать это точное требование Стандарта как одно простое объявление.