根据cppreference.com size_t在几个头中定义,即
<cstddef>
<cstdio>
<cstring>
<ctime>
而且,自C ++ 11起,
<cstdlib>
<cwchar>
首先,我想知道为什么会这样。这不违背DRY原则吗?但是,我的问题是:
我应使用上述标题中的哪一个size_t?有关系吗?
根据cppreference.com size_t在几个头中定义,即
<cstddef>
<cstdio>
<cstring>
<ctime>
而且,自C ++ 11起,
<cstdlib>
<cwchar>
首先,我想知道为什么会这样。这不违背DRY原则吗?但是,我的问题是:
我应使用上述标题中的哪一个size_t?有关系吗?
<cstddef>的std::size_t
std::size_t,OP并不主张使用传统的C函数,只是观察有关它们共享typedef的引用。我怀疑阅读此线程的任何人都会因此而被误导使用遗留类型/函数,但是如果您要确保他们不会使用遗留类型/函数,那就足够公平了!
Answers:
假设我想最小化导入的函数和类型,cstddef因为它不声明任何函数,而仅声明6种类型。其他的则专注于对您可能无关紧要的特定域(字符串,时间,IO)。
请注意,cstddef仅保证define std::size_t,即size_t在namespace中定义std,尽管它也可以在全局命名空间中提供此名称(有效地是plain size_t)。
相反,stddef.h(这也是C中可用的头)保证size_t在全局名称空间中定义,并且还可以提供std::size_t。
size_tfrom cstddef相同并且将始终与其他相同?似乎应该有一个具有相同定义的通用头文件,如size_t...
cstddef。
<cstddef>,也可以全部包含一些刚刚定义的内部标头size_t。
csttddef在回答一个错字?也许 cstddef是什么意思?
实际上,几个标头的提要(包括在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不包含标题的形式获得
如果你打算引进在你的代码的类型定义反正(即,因为你写的容器,并希望提供一个size_type类型定义),您可以使用全局sizeof,sizeof...或alignof运营商来定义你的类型,而不包括任何标题,因为在所有运营商必然也会返回std::size_t每标准定义,您可以decltype在它们上使用:
using size_type = decltype(alignof(char));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*);
不引入size_t,std或std::size_t与
除非名称通过包含适当的标头声明,否则引用
std或std::size_t格式不正确。
std::size_t尽管可能有多个typedef引用同一命名空间中的同一类型,但用户可能无法重新定义。
虽然,根据7.1.3 / 3完全存在size_t内部的多个定义,但根据17.6.4.2.1 / 1不允许添加任何声明:stdnamespace std
如果C ++程序的声明或定义添加到名称空间std或名称空间std中的名称空间,则除非定义,否则其行为是不确定的。
为size_t名称空间添加适当的typedef 不会违反7.1.3,但是会违反17.6.4.2.1并导致未定义的行为。
说明性:尽量不要误解7.1.3,不要在其中添加声明或定义std(除了一些类型特殊化的情况,其中typedef不是模板特殊化)。扩展namespace std
std重复定义的typedef 是无效的,因为重复的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
size_t?
size_t。您可以更方便地将其定义为using size_t = decltype( sizeof( 42 ) )。但是没有必要,因为<stddef.h>成本几乎为零。
您可以不使用标题:
using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); // The shortest is my favourite.
using size_t = decltype(sizeof "anything");
这是因为C ++标准要求:
的结果
sizeof和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.");
还要注意,typedef在全局和std命名空间中进行此声明是完全可以的,只要它与typedef相同typedef-name的所有其他声明匹配(对不匹配的声明会发出编译器错误)。
这是因为:
§7.1.3.1typedef -name不会像类声明(9.1)或枚举声明那样引入新类型。
§7.1.3.3在给定的非类范围内,typedef可以使用说明符来重新定义在该范围内声明的任何类型的名称,以引用它已经引用的类型。
持怀疑态度的人说,这是在名称空间中添加了新类型 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中,现在有一种方法可以将标准的确切要求记为一个简单的声明。
size_t!定义!” 一分钟后,玛丽说:“天哪!size_t在标准库头中有7个定义,在汤姆正在编辑的项目头中!第三方库中可能还有更多的定义!” xkcd.com/927
size_t,但这并不能回答OP的真正问题:好像我要求在标头中FILE声明该标头,并且建议您编写自己的标头。