根据cppreference.com size_t
定义的几个标题,即
<cstddef>
<cstdio>
<cstring>
<ctime>
Run Code Online (Sandbox Code Playgroud)
而且,从C++ 11开始,也在
<cstdlib>
<cwchar>
Run Code Online (Sandbox Code Playgroud)
首先,我想知道为什么会这样.这与DRY原则是否相矛盾?但是,我的问题是:
我应该使用上面哪个标题来使用size_t
?它有关系吗?
Sea*_*ean 75
假设我想最小化我导入的函数和类型,我会去,cstddef
因为它没有声明任何函数,只声明了6种类型.其他人专注于对您而言无关紧要的特定领域(字符串,时间,IO).
请注意,cstddef
只保证定义std::size_t
,即size_t
在命名空间中定义std
,尽管它也可以在全局命名空间中提供此名称(实际上,简单size_t
).
相反,stddef.h
(也是C中可用的头)保证size_t
在全局命名空间中定义,也可以提供std::size_t
.
Pix*_*ist 42
事实上,几个标题的概要(包括在C++标准中)特别包括size_t
以及进一步的标题定义类型size_t
(基于C标准,因为<cX>
标题只是ISO C <X.h>
标题,其中size_t
未标明删除的标记更改).
但是,C++标准是指<cstddef>
定义的std::size_t
因此,由于<cstddef>
只引入类型而没有函数的事实,我会坚持使用这个标题来std::size_t
提供.
请注意以下几点:
std::size_t
可以使用decltype
而不包括标题来获得类型
如果你打算在你的代码引入一个typedef反正(即,因为你写的容器,并希望提供一个size_type
类型定义),您可以使用全局sizeof
,sizeof...
或alignof
运营商来定义你的类型,而不包括任何标题,因为在所有运营商必然也会返回std::size_t
每标准定义,您可以使用decltype
它们:
using size_type = decltype(alignof(char));
Run Code Online (Sandbox Code Playgroud)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*);
Run Code Online (Sandbox Code Playgroud)
不引入size_t
,std
或std::size_t
与
除非通过包括适当的标题声明了名称,否则提及
std
或std::size_t
形成不良.
用户可能不会重新定义,std::size_t
尽管可能有多个typedef在同一名称空间中引用相同的类型.
虽然,根据7.1.3/3,size_t
内部的多个定义的出现std
完全有效,但不允许按照17.6.4.2.1/1添加任何声明:namespace std
如果C++程序向命名空间std或命名空间std中的命名空间添加声明或定义,则它是未定义的,除非另有说明.
为size_t
命名空间添加正确的typedef 并不违反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
Run Code Online (Sandbox Code Playgroud)
你可以没有标题:
using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); // The shortest is my favourite.
using size_t = decltype(sizeof "anything");
Run Code Online (Sandbox Code Playgroud)
这是因为 C++ 标准要求:
sizeof
and的结果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.");
Run Code Online (Sandbox Code Playgroud)
另请注意,typedef
在全局和std
命名空间中进行此声明是完全没问题的,只要它与typedef
具有相同typedef 名称的所有其他声明相匹配(在不匹配的声明中会发出编译器错误)。
这是因为:
§7.1.3.1 typedef-name不会像类声明 (9.1) 或枚举声明那样引入新类型。
§7.1.3.3 在给定的非类作用域中,typedef
可以使用说明符重新定义在该作用域中声明的任何类型的名称,以引用它已经引用的类型。
怀疑论者说,这构成了向 namespace 中添加新类型std
,并且标准明确禁止这种行为,这就是 UB ,仅此而已;我不得不说,这种态度等于忽视和否认对潜在问题的更深入理解。
该标准禁止在命名空间中添加新的声明和定义,std
因为这样做可能会将标准库弄得一团糟,并把他的整条腿都打掉。对于标准编写者来说,让用户专注于一些特定的事情并禁止做任何其他事情来更好地衡量更容易,而不是禁止用户不应该做的每一件事,并冒着错过重要的事情(和那条腿)的风险。过去,当要求不使用不完整类型实例化任何标准容器时,他们这样做了,而实际上一些容器完全可以做到(参见Matthew H. Austern 的标准图书馆员:不完整类型的容器):
......最后,这一切似乎太模糊,太难理解了;标准化委员会认为除了说 STL 容器不应该与不完整的类型一起工作之外,别无选择。为了更好地衡量,我们也将该禁令应用于标准库的其余部分。
... 回想起来,现在对技术有了更好的理解,这个决定似乎仍然基本正确。是的,在某些情况下,可以实现一些标准容器,以便用不完整的类型实例化它们——但很明显,在其他情况下,这将是困难的或不可能的。我们尝试的第一个测试,使用
std::vector
,碰巧是一个简单的案例,这主要是偶然的。
鉴于语言规则要求std::size_t
精确decltype(sizeof(int))
,做namespace std { using size_t = decltype(sizeof(int)); }
是不破坏任何事情的事情之一。
在 C++11 之前,没有decltype
也没有办法sizeof
在不涉及大量模板的情况下在一个简单的语句中声明结果的类型。size_t
在不同的目标架构上为不同的类型设置别名,但是,仅仅为 的结果添加新的内置类型并不是一个优雅的解决方案sizeof
,并且没有标准的内置 typedef。因此,当时最便携的解决方案是将size_t
类型别名放在某些特定的标题和文档中。
在 C++11 中,现在有一种方法可以将标准的确切要求写成一个简单的声明。