C++ “大小”应该包含哪个标题?

C++ “大小”应该包含哪个标题?,c++,typedef,C++,Typedef,根据size\u,在几个标题中定义了,即 <cstddef> <cstdio> <cstring> <ctime> 而且,自C++11以来,在 <cstdlib> <cwchar> 首先,我想知道为什么会这样。这难道不违背原则吗 要使用size\u t,我应该包括上面哪一个标题?这有什么关系吗?没有标题也可以: using size_t = decltype(sizeof(int)); using size_t

根据
size\u,在几个标题中定义了
,即

<cstddef>
<cstdio>
<cstring>
<ctime>

而且,自C++11以来,在

<cstdlib>
<cwchar> 

首先,我想知道为什么会这样。这难道不违背原则吗


要使用
size\u t
,我应该包括上面哪一个标题?这有什么关系吗?

没有标题也可以:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

这是因为C++标准要求:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");
sizeof
sizeof…
的结果是一个类型为
std::size\u t
的常量。[注:
std::size\u t
在标准标题
(18.2)中定义。-结束注]

换句话说,该标准要求:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");
static_assert(std::is_same::value,
“这永远不会失败。”);

还要注意的是,在全局和
std
命名空间中进行
typedef
声明是完全可以的,只要它匹配相同typedef名称的所有其他
typedef
声明(不匹配的声明会发出编译器错误)

这是因为:

  • §7.1.3.1 typedef名称不会像类声明(9.1)或枚举声明那样引入新类型

  • §7.1.3.3在给定的非类别范围内,
    typedef
    说明符可用于重新定义该范围内声明的任何类型的名称,以引用其已引用的类型


对怀疑论者说,这构成了在名称空间
std
中添加了一种新类型,并且该标准明确禁止此类行为,这就是UB,仅此而已;我必须说,这种态度相当于忽视和否认对根本问题的深入理解

标准禁止在命名空间
std
中添加新的声明和定义,因为这样做可能会把标准库搞得一团糟,让用户一筹莫展。对于标准编写者来说,更容易让用户专门处理一些特定的事情,并禁止做其他任何事情,而不是禁止用户不应该做的每一件事情,并冒着错过一些重要的事情(和那一条腿)的风险。在过去,当要求任何标准容器都不能用不完整的类型实例化时,他们就这样做了,而事实上,一些容器也可以这样做(请参阅):

。。。最后,这一切似乎太模糊,理解得太少;标准化委员会认为除了说STL容器不应该使用不完整的类型外,没有其他选择。为了更好的衡量,我们也将这一禁令应用于标准库的其余部分

。。。回顾过去,现在人们对这项技术有了更好的理解,这个决定似乎基本上仍然是正确的。是的,在某些情况下,实现一些标准容器是可能的,这样就可以用不完整的类型对它们进行实例化——但也很明显,在其他情况下,这将是困难或不可能的。我们尝试的第一个测试(使用
std::vector
)碰巧是一个简单的案例,这很有可能

考虑到语言规则要求
std::size_t
完全是
decltype(sizeof(int))
,使用size_t=decltype(sizeof(int));}执行
名称空间std{是不会破坏任何东西的事情之一

在C++11之前,没有
decltype
,因此无法在一个简单语句中声明
sizeof
结果的类型,而不涉及大量模板
size\u t
在不同的目标体系结构上为不同的类型添加别名,但是,仅仅为
sizeof
的结果添加一个新的内置类型并不是一个优雅的解决方案,并且没有标准的内置TypeDef。因此,当时最可移植的解决方案是将
size\t
类型别名放在某个特定的头中,并记录该别名


在C++11中,现在有一种方法可以将标准的确切要求写为一个简单的声明。

假设我想最小化我导入的函数和类型,我会使用
cstdef
,因为它不声明任何函数,只声明6种类型。其他人则关注于对您可能不重要的特定域(字符串、时间、IO)

请注意,
cstdef
仅保证定义
std::size\u t
,即在名称空间
std
中定义
size\u t
,尽管它也可以在全局名称空间中提供此名称(实际上是普通的
size\u t


相反,
stddef.h
(也是C中可用的头文件)保证在全局名称空间中定义
size\t
,并且还可以提供
std::size\t
,所有标准库头文件都具有相同的定义;在您自己的代码中包含哪一个并不重要。在我的计算机上,我在
\u 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

实际上,几个标题的概要(包含在C++标准中)具体包括“代码> SIEZYT 以及进一步的标题定义了类型<代码> SiZeSt<<代码>(基于C标准作为<代码> <代码>标题仅是ISO C代码> <代码>标题,其中注明“删除<代码> siZeSt未被删除”。 <> >强> C++标准< /强>,<强>指<代码> <代码>定义为<代码>:

  • 在18.2类型中
  • 在第5.3.3节中
  • 在3.7.4.2解除分配功能(参见18.2)中,以及
  • 在3.7.4.1分配功能中(也参考18.2)
因此,由于
只引入类型而不引入函数,因此我坚持使用此标题以使
std::size\t
可用


注意几件事:

  • void* operator new(std::size_t);
    void* operator new[](std::size_t);
    void operator delete(void*);
    void operator delete[](void*);