Does "std::size_t" make sense in C++?
C++Size TC++ Problem Overview
In some code I've inherited, I see frequent use of size_t
with the std
namespace qualifier. For example:
std::size_t n = sizeof( long );
It compiles and runs fine, of course. But it seems like bad practice to me (perhaps carried over from C?).
Isn't it true that size_t
is built into C++ and therefore in the global namespace? Is a header file include needed to use size_t
in C++?
Another way to ask this question is, would the following program (with no includes) be expected to compile on all C++ compilers?
size_t foo()
{
return sizeof( long );
}
C++ Solutions
Solution 1 - C++
There seems to be confusion among the stackoverflow crowd concerning this
::size_t
is defined in the backward compatibility header stddef.h
. It's been part of ANSI/ISO C
and ISO C++
since their very beginning. Every C++ implementation has to ship with stddef.h
(compatibility) and cstddef
where only the latter defines std::size_t
and not necessarily ::size_t
. See Annex D of the C++ Standard.
Solution 2 - C++
Section 17.4.1.2 of the C++ standard, paragraph 4, states that:
"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."
This includes items found in headers of the pattern cname, including cstddef, which defines size_t.
So std::size_t is in fact correct.
Solution 3 - C++
You can get size_t
in the global namespace by including, for example, <stddef.h>
instead of <cstddef>
. I can't see any obvious benefit, and the feature is deprecated.
Solution 4 - C++
size_t is not built into C++. And it is not defined by default. This one doesn't compile with GCC:
int main(int argc, char** argv) {
size_t size;
}
That said, size_t is part of POSIX and if you use only basic things like <cstdlib>
, you will likely end up having it defined.
You could argue that std::size_t is the C++ equivalent of size_t. As Brian pointed out, std:: is used as namespace to avoid setting global variables which don't fit everybody. It's just like std::string, which could also have been defined in the root namespace.
Solution 5 - C++
std::size_t n = sizeof( long );
Actually, you haven't asked what specifically seems to be a bad practice int the above. Use of size_t, qualification with std namespace,...
As the C++ Standard says (18.1), size_t is a type defined in the standard header
I'd consider including
size_t is not a built-in type in C++. It is a type defined to specify what kind of integral type is used as a return type of sizeof() operator, because an actual return type of sizeof() is implementation defined, so the C++ Standard unifies by defining size_t.
> would the following program (with no > includes) be expected to compile on > all C++ compilers? > > size_t foo() > { > return sizeof( long ); > }
The C++ Standard says (1.4):
The names defined in the library have namespace scope (7.3). A C ++ translation unit (2.1) obtains access to these names by including the appropriate standard library header (16.2).
The size_t is a name defined within std namespace, so every program that uses this name should include corresponding header,
Next, the 3.7.3 chapter says:
However, referring to std, std::bad_alloc, and std::size_t is ill-formed unless the name has been declared by including the appropriate header.
Given that, program using size_t but not including
Solution 6 - C++
Sometimes other libraries will define their own size_t. For example boost. std::size_t specifies that you definitely want the c++ standard one.
size_t is a c++ standard type and it is defined within the namespace std.
Solution 7 - C++
The GNU compiler headers contain something like
typedef long int PTRDIFF_TYPE; typedef unsigned long int SIZE_TYPE;
Then stddef.h constains something like
typedef PTRDIFF_TYPE ptrdiff_t; typedef SIZE_TYPE size_t;
And finally the cstddef file contains something like
#include <stddef.h>namespace std {
using ::ptrdiff_t; using ::size_t;
}
I think that should make it clear. As long as you include <cstddef> you can use either size_t or std::size_t because size_t was typedefed outside the std namespace and was then included. Effectively you have
typedef long int ptrdiff_t; typedef unsigned long int size_t;namespace std {
using ::ptrdiff_t; using ::size_t;
}
Solution 8 - C++
I think the clarifications are clear enough. The std::size_t
makes good sense in C++ and ::size_t
make (at least) good sense in C.
However a question remain. Namely whether it is safe to assume that ::size_t
and std::size_t
are compatible?
From a pure typesafe perspective they are not necessarily identical unless it is defined somewhere that they must be identical.
I think many are using something a la:
----
// a.hpp
#include <string>
void Foo( const std::string & name, size_t value );
-----
// a.cpp
#include "a.hpp"
using namespace std;
void Foo( const string & name, size_t value )
{
...
}
So in the header you defintely use the ::size_t
while in the source file you'll use std::size_t
. So they must be compatible, right? Otherwise you'll get a compiler error.
/Michael S.