According to cppreference.com size_t
is defined in several headers, namely
<
In fact the synopsis (included in the C++ standard) of several headers specifially include size_t
as well as further headers define the type size_t
(based on the C standard as the <cX>
headers are just ISO C <X.h>
headers with noted changes where removal of size_t
is not indicated).
The C++ standard however, refers to <cstddef>
for the definition of std::size_t
Therefore and because of the fact that <cstddef>
only introduces types and no functions, I'd stick to this header to make std::size_t
available.
Note a few things :
The type of std::size_t
is obtainable using decltype
without including a header
If you're planning to introduce a typedef in your code anyway (i.e. because you write a container and want to provide a size_type
typedef) you can use the global sizeof
, sizeof...
or alignof
operators to define your type without including any headers at all since theose operators return std::size_t
per standard definition and you can use decltype
on them:
using size_type = decltype(alignof(char));
std::size_t
is not per se globally visible although functions with std::size_t
arguments are.
The implicitly declared global allocation and deallocation functions
void* operator new(std::size_t);
void* operator new[](std::size_t);
void operator delete(void*);
void operator delete[](void*);
do NOT introduce size_t
, std
or std::size_t
and
referring to
std
orstd::size_t
is ill-formed unless the name has been declared by including the appropriate header.
The user may not redefine std::size_t
although it is possible to have multiple typedefs referring to the same type in the same namespace.
Although, the occurrence of multiple definitions of size_t
within std
is perfectly valid as per 7.1.3 / 3, it is not allowed to add any declarations to namespace std
as per 17.6.4.2.1 / 1:
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.
Adding a proper typedef for size_t
to the namespace does not violate 7.1.3 but it does violate 17.6.4.2.1 and leads to undefined behaviour.
Clarification: Try not to misinterpret 7.1.3 and do not add declarations or definitions to std
(except a few template specialization cases where a typedef is not a template specialization). Extending the namespace std
All standard library header files have the same definition; it does not matter which one you include in your own code. On my computer, I have the following declaration in _stddef.h
. This file is included by every file you listed.
/*
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
You could do without a header:
using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); // The shortest is my favourite.
using size_t = decltype(sizeof "anything");
This is because the C++ standard requires:
The result of
sizeof
andsizeof...
is a constant of typestd::size_t
. [ Note:std::size_t
is defined in the standard header<cstddef>
(18.2). — end note ]
In other words, the standard requires:
static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
"This never fails.");
Also note, that it is perfectly fine to make this typedef
declaration in the global and in std
namespace, as long as it matches all other typedef
declarations of the same typedef-name (a compiler error is issued on non-matching declarations).
This is because:
§7.1.3.1 A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does.
§7.1.3.3 In a given non-class scope, a typedef
specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.
To sceptics saying that this constitutes an addition of a new type into namespace std
, and such an act is explicitly prohibited by the standard, and this is UB and that is all there to it; I have to say that this attitude amounts to ignoring and denying deeper understanding of the underlying issues.
The standard bans adding new declarations and definitions into namespace std
because by doing so the user may make a mess of the standard library and shoot his entire leg off. For the standard writers it was easier to let the user specialize a few specific things and ban doing anything else for good measure, rather than ban every single thing which the user should not do and risk missing something important (and that leg). They did it in the past when requiring that no standard container shall be instantiated with an incomplete type, while in fact some containers could well do (see The Standard Librarian: Containers of Incomplete Types by Matthew H. Austern):
... In the end, it all seemed too murky and too poorly understood; the standardization committee didn't think there was any choice except to say that STL containers aren't supposed to work with incomplete types. For good measure, we applied that prohibition to the rest of the standard library too.
... In retrospect, now that the technology is better understood, that decision still seems basically right. Yes, in some cases it's possible to implement some of the standard containers so that they can be instantiated with incomplete types — but it's also clear that in other cases it would be difficult or impossible. It was mostly chance that the first test we tried, using
std::vector
, happened to be one of the easy cases.
Given that the language rules require std::size_t
to be exactly decltype(sizeof(int))
, doing namespace std { using size_t = decltype(sizeof(int)); }
is one of those things that do not break anything.
Prior to C++11 there was no decltype
and thus no way to declare the type of sizeof
result in one simple statement without getting a good deal of templates involved. size_t
aliases different types on different target architectures, however, it would not be an elegant solution to add a new built-in type just for the result of sizeof
, and there are no standard built-in typedefs. Hence, the most portable solution at the time was to put size_t
type alias in some specific header and document that.
In C++11 there is now a way to write down that exact requirement of the standard as one simple declaration.
Assuming I wanted to minimize the functions and types I was importing I'd go with cstddef
as it doesn't declare any functions and only declares 6 types. The others focus on particular domains (strings, time, IO) that may not matter to you.
Note that cstddef
only guarantees to define std::size_t
, that is, defining size_t
in namespace std
, although it may provide this name also in the global namespace (effectively, plain size_t
).
In contrast, stddef.h
(which is also a header available in C) guarantees to define size_t
in the global namespace, and may also provide std::size_t
.