According to cppreference.com size_t is defined in several headers, namely
<cstddef>
<cstdio>
<cstring>
<ctime>
And, since C++11, also in
<cstdlib>
<cwchar>
First of all, I wonder why this is the case. Isn't this in contradiction to the DRY principle?
Which one of the above headers should I include to use size_t? Does it matter at all?
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.
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
in 18.2 Types,
in 5.3.3 Sizeof,
in 3.7.4.2 Deallocation functions (which refers to 18.2) and
in 3.7.4.1 Allocation functions (also refers to 18.2).
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 or std::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 and sizeof... is a constant of type std::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.
Related
When should one include headers for built-in types?
<new> for new (seems for sophisticated overloadings it is really needed); it can be just used.
(edit: wrong example (see answers)) <typeinfo> for std::type_info; it can be just acquired by using typeid operator
(edit: wrong example (see answers)) <initializer_list> for std::initizlizer_list; it is just result of auto l = {1, 2, 3}; or temporary in for (int i : {1, 2, 3}) {}
<cstddef>/<cstdio>/<cstring>/<ctime> for std::size_t; it can be given as result of operator sizeof val or sizeof(Type)
<cstddef> for std::nullptr_t; decltype(nullptr)
<cstddef> for std::ptrdiff_t; decltype(std::declval<int *>() - std::declval<int *>())
<tuple> for some functionality of structured bindings
maybe others
Are there cases when inclusion of corresponding headers is mandatory?
Strictly speaking, not all of your examples behave as you seem to expect. For instance
[expr.typeid]
6 If the header <typeinfo> is not included prior to a use of
typeid, the program is ill-formed.
[dcl.init.list]
2 ... The template std::initializer_list is not predefined; if
the header <initializer_list> is not included prior to a use of
std::initializer_list — even an implicit use in which the type is
not named — the program is ill-formed.
So there's two examples right off the bat. And sure, you can get by without including some headers, for instance
using size_t = decltype(sizeof(0));
using nullptr_t = decltype(nullptr);
But in general, the way to guarantee with complete certainty that we get well-defined results, is to include the proper header for standard types.
Are there cases when inclusion of corresponding headers is mandatory?
I am not a language lawyer, and C++11 is too difficult to master for me (see n3337), but on implementations like GCC or Clang a standard header can and often does contain compiler specific tricks like #pragmas, function attributes, or builtins.
Today at end of 2019, GCC uses such tricks for at least <cstdarg> and actually in many other cases (try grep -rn __attribute__ /usr/lib/gcc/x86_64-linux-gnu/8/ on a recent Debian, for instance).
My understanding is that a standard header might not even exist as a file on your system. It could be magic inside the compiler, processing #include <map> specifically to change the compiler's state. However, I know no compiler doing that in 2019. According to rumors, VisualAge did that in the previous century.
So I believe that the inclusion of standard headers is required, when you use them.
I have been successfully using cxx-prettyprint: A C++ Container Pretty-Printer to log container values. (See also Pretty-print C++ STL containers) It's working like a charm even on the old VS-2005 (VC8) compiler (with the prettyprint98.hpp header), also works well on VS2017-2019 when using it e.g. to make container values printable in Unit Tests.
While studying its interoperability with Boost.Format, I found to my surprise that it simply works out of the box, when other questions suggest it shouldn't because ADL should fail for a user provided output operator.
Looking into the cxx-pp header I found that it simply works because the library does define its output operator(s) inside the std namespace:
// Main magic entry point: An overload snuck into namespace std.
// Can we do better?
namespace std
{
// Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
inline typename enable_if< ::pretty_print::is_container<T>::value,
basic_ostream<TChar, TCharTraits> &>::type
operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
{
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
}
....
Obviously the authors were not 100% confident with this: qq "Can we do better?"
Adding something to the std namespace is formally UB:
[C++11: 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. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
So, is this in cxx-pp formally UB, or is it a template specialization (It doesn't seem like one to me).
Comments as to the practical impact of this, iff UB, would be very welcome.
This is covered by [namespace.std]/1 in the standard (which is quoted in the question but reproducing it here as it is also the answer):
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.
There isn't any "otherwise specified" for overloads of operator<< for new user-defined types.
So the behaviour is just undefined (with no diagnostic required).
In practical terms it seems like that either the code will work or it won't, but as with all UB we should be careful not to rule anything else out.
I am currently going through the 5th edition of C++ Primer by Lahoie, Lippman and Moo and have been struggling with a few things.
Firstly, I just wanted to confirm, when using any of the cctype functions, I have to make sure I include the header, right? Because, initially, I forgot to include it and yet it still ran. That's really confused me.
Also, I was browsing for a different problem (which I'll get to) and found another issue haha! When using anything from cctype, are I supposed to write it as std::/write using std::, e.g. if I use the tolower either write std::tolower at every instance/write a using statement for it. This would make sense as it did say that they are "defined in the std namespace" but I didn't realise and have been writing it without and haven't had an issue. And I'm guessing similar for size_t, right?
Speaking of size_t, I have an issue. This is my code:
// Exercise Section 3.5.2., Exercise 3.30
#include <iostream>
#include <cstddef>
using std::cout; using std::endl;
int main()
{
constexpr size_t num_size = 10;
int num[num_size] = {};
for (size_t n = 0; n < num_size; ++n) {
num[n] = n;
cout << num[n] << endl;
}
return 0;
}
So the code is supposed define an array of 10 ints and give each element the same value as its position in the array.
It runs correctly, but I am receiving an error at the num[n]=n part. It says Implicit conversion loses integer precision: size_t (aka 'unsigned long') to int.
I understand what this means, but my issue is that the book says "when we use a variable to subscript an array, we normally should define that variable to type size_t". I have done this and it gives this error. It does run fine but it seems like that sort of thing that can lead to errors.
P.S. In this code, like I asked above, should I have using std::size_t?
Must I include the header even though it works without?
Yes, you must always include at least one header providing each definition / declaration you need, unless the exact prototype / type definition is guaranteed and you put it directly into your source code.
Some standard headers may include others, which might let you get away with being sloppy some of the time, but you will rue it the day you upgrade / port to a different implementation.
I read all the declarations and definitions are "defined in the std namespace" but I didn't realise and have been writing it without and haven't had an issue. And I'm guessing similar for size_t, right?
Yes, it's the same. Due to compatibility, it is possible for the <c...> headers adopted by inclusion from C / Unicode to also provide their symbols in the global namespace.
17.6.1.2 Headers [headers]
1 Each element of the C++ standard library is declared or defined (as appropriate) in a header.175
2 The C++ standard library provides 55 C++ library headers, as shown in Table 14.
3 The facilities of the C standard Library are provided in 26 additional headers, as shown in Table 15.
4 Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
5 Names which are defined as macros in C shall be defined as macros in the C++ standard library, even if C grants license for implementation as functions. [ Note: The names defined as macros in C include the following: assert, offsetof, setjmp, va_arg, va_end, and va_start. —end note ]
6 Names that are defined as functions in C shall be defined as functions in the C++ standard library.176
7 Identifiers that are keywords or operators in C++ shall not be defined as macros in C++ standard library headers.177
8 D.5, C standard library headers, describes the effects of using the name.h (C header) form in a C++ program. 178
In my example program I used size_t for the array index. That works, though I get a warning. Should I have done so, and could it in general lead to errors?
Well, naturally the same about namespace std applies, as you guessed.
As to the rest, there's a wonderful phrase: "Good advice comes with a rationale".
The reason you should use std::size_t for indices is that this type a) signals to readers that it's a size or index and b) it is guaranteed to be big enough.
In your case, a lowly int, with its guaranteed minimum maximum of 215-1 would have been perfectly fine.
An alternative is just casting to the proper type on assignment.
You asked:
Firstly, I just wanted to confirm, when using any of the cctype functions, I have to make sure I include the header, right?
Yes, that is right. You might get some function declarations or other declarations indirectly but that is not portable code. You should understand where the standard says a declaration is available and include that header file before using a function, a type, etc.
You asked:
And I'm guessing similar for size_t, right?
Yes, you should use std::size_t.
There is an SO post related to the topic. Browse Difference between size_t and std::size_t.
You asked:
In this code, like I asked above, should I have using std::size_t?
In the loop, it's OK to use int too. The suggestion to use std::size_t for indexing an array is a good suggestion but is not inviolable.
If you choose to use size_t for n, it's OK to use static_cast to convert it to an int to get rid of the compiler warning/error.
num[n] = static_cast<int>(n);
You declare your array as
int num[num_size] = {};
This means it is an array of int that has 10 elements.
Then you say
for (size_t n = 0; n < num_size; ++n)
num[n] = n;
Note that n is of type size_t aka unsigned long. Therefore you are putting unsigned long values into your int array, so they are being implicitly converted to int values.
The standard headers put a bunch of stuff in the global namespace. Ideally they wouldn't, but they do. Usually that's because something is really a macro rather than a typedef or function.
You can sometimes get away without including headers because some other header that you have included includes the missing one.
I have to make sure I include the header, right? Because, initially, I
forgot to include it and yet it still ran.
Some standard headers can include other headers. However it is a good idea to include a header explicitly if some declarations from the header are used in the program. It may occur such a way that in other implementations of the included headers the required header will not be included and the compiler will issue an error.
. This would make sense as it did say that they are "defined in the
std namespace" but I didn't realise and have been writing it without
and haven't had an issue.
The C++ Standard allows compilers to place C standard functions in the global namespace. Though even in this case it is better to specify explicitly namespace std where the function will be declared in any case.
As for the last question then the elements of the array have type int while you assign to them values of type size_t The problem is that type int can not accomodate all values of type size_t and the compiler warns you about this. You could explicitly specify casting that to say the compiler that you know what you are doing.
num[n] = ( int )n;
or
num[n] = static_cast<int>( n );
In C++11 I can choose whether I want to use the types defined in with or without the namespace std::
At least my compiler (g++ 4.7) accepts both variants.
My question is: What is the recommended way to use the typedefs from cstdint. With or without the namespace? What are the advantages or disadvantages? Or is it only a matter of style?
so variant a):
#include <cstdint>
std::uint8_t n = 21;
resp:
#include <cstdint>
using std::uint8_t;
uint8_t n = 21;
or variant b):
#include <cstdint>
uint8_t n = 21;
Prefer names declared in the std namespace. The reason is given in §17.6.1.3/4 (ISO/IEC 14882:2011(E), C++11):
Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
If you use the names from the <cname> headers without std, your program is relying on unspecified requirements.
This was different in C++03 and earlier where names were only supposed to appear in the std namespace. However, the reality was that many implementations were simply injecting the contents of the C standard library headers <name.h> into std and so this was accommodated for in C++11. The corresponding section (§17.4.1.2/4) from the C++03 standard says:
Except as noted in clauses 18 through 27, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in ISO/IEC 9899:1990 Programming Languages C (Clause 7), or ISO/IEC:1990 Programming Languages—C AMENDMENT 1: C Integrity, (Clause 7), as appropriate, as if by inclusion. In the C++ Standard Library, however, the declarations and definitions (except for names which are defined as macros in C) are within namespace scope (3.3.5) of the namespace std.
Further to this, qualifying names with std:: helps to avoid collisions - you know exactly what you're getting if you fully qualify it. If you're really going to do using namespace std or using std::something, at least do it in as minimal a scope as you can.
In C++11, for the C headers that are explicitly named in the C++ standard, the following holds:
An implementation is required for the <foo.h> versions to add them in the global namespace, and allowed to add them to the std:: namespace.
An implementation is required for the <cfoo> versions to add them in the std:: namespace, and allowed to add them to the global namespace.
The reason for wrapping things in the std namespace in the <cstdint> header is to avoid name collisions, which are quite unpleasant when they happen. However, in this case, it is very unlikely that the types will be found somewhere else. So I would use <stdint.h>, especially because this feature was introduced in C before it was added to C++, and hence the <stdint.h> header is older than <cstdint>, and therefore available in older compilers.
If you have decided that you want these names in the global namespace, you should also prefer <stdint.h> to <cstdint> followed by using namespace std, as the latter will dump all the other std stuff from other <cfoo> headers yhou have included into the global namspace too, which you probably do not want, as many other standard names are much more collision-prone than the likes of uint8_t.
Include <cstdint> and use std:: or include <stdint.h> to use unqualified type names. There are some platforms (e.g. QNX SDP 6.6) on which <cstdint> doesn't declare those types in the global namespace.
My personal style is to always fully qualify names so it is clear where they come from. That is, I would use std::uint8_t. That is, I would include <cstdint> and use qualified names.
That said, note that use of std::uint8_t is only indicated if you really mean to use a type with exactly 8 bits. If the platform you are running your code on doesn't have such a type, e.g., because it uses 9 bit units as its basic entity, the program is supposed not to compile. If you want to use the smallest unsigned with 8 bits available, you want to use uint_least8_t.
It seems on XCode I need to use std::size_t instead of just size_t on Visual C++. But this is a pain as I don't really want to have to #include <cstddef> and change every size_t to std::size_t in my code... in my Windows code size_t just works without including any additional files.
Is there a way to make my existing code work in XCode, (maybe through the .pch file?) or are GCC/MSVC++ fundamentally different in this regard and my code needs to use std::size_t in order to be cross-platform?
According to the C++03 standard, 17.4.1.2.4:
Except as noted in clauses 18 through 27, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in ISO/IEC 9899:1990 Programming Languages C (Clause 7), or ISO/IEC:1990 Programming Languages—C AMENDMENT 1: C Integrity, (Clause 7), as appropriate, as if by inclusion. In the C++ Standard Library, however, the declarations and definitions (except for names which are defined as macros in C) are within namespace scope (3.3.5) of the namespace std.
In other words, by choosing to use <cstddef> instead of <stddef.h>, you're specifically asking for the type size_t to be within the namespace std.
So, here are the choices:
Use <stddef.h> instead, so size_t is in the top-level namespace, as suggested by Jesse Good.
Use <cstddef> and use std::size_t.
Use <cstddef> and use a using declaration to pull size_t into the top-level namespace, as suggested by cnicutar.
Of course you could rely on the fact that one particular version of one compiler/library/platform lets you get away with it, or write different code for each platform, or wrap the whole thing up with autoconf, or write a code generator or sed-based preprocessor, or whatever… but why?
Perhaps saying this somewhere near the top ?
using std::size_t;
Use #include <stddef.h>.
So, what's the difference between #include <stddef.h> and #include <cstddef>?
<cstddef> is a C++ header and is guaranteed to define all symbols in the std namespace and also may define things in the global namespace.
<stddef.h>is a C header and is guaranteed to define all symbols in the global namespace and may also define things in the std namespace.
So, as you said on Visual Studio, size_t can be used because it injects size_t into the global namespace for you (possibly by already including "stddef.h"). If you want that to work on any compiler include stddef.h.
(However, as a pure C++ fan, I personally prefer std::size_t).