在C++中,"std::size_t"有意义吗?

66

在我继承的一些代码中,我经常看到size_tstd命名空间限定符一起使用。例如:

std::size_t n = sizeof( long );

当然,它能够编译和运行。但我认为这是一种不好的做法(可能是从C语言中继承下来的?)。

在C++中,size_t已经内置并且位于全局命名空间中,这是真的吗?在C++中使用size_t是否需要包含头文件?

换句话说,以下代码(不包含任何头文件)是否能够在所有C++编译器上预期地进行编译

size_t foo()
{
    return sizeof( long );
}

13
C语言没有命名空间(namespaces)。 - wnoise
1
它已经包含在 C++ 中,当您 #include <cstddef> 时,位于 std 命名空间中。请查看下面的答案。 - Don Wakefield
2
这并不是“另一种方式来提出这个问题” - 它是一个不同的问题:main函数返回int。 - fizzer
8个回答

137

在stackoverflow社区中似乎存在一些关于这个问题的混淆。

::size_t被定义在向后兼容头文件stddef.h中。自从ANSI/ISO CISO C++问世以来,::size_t就一直是其中的一部分。每个C++实现都必须随附stddef.h(兼容性)和cstddef,只有后者定义了std::size_t并且不一定定义了::size_t。请参见C++标准的附录D。


14
这是绝对最好的答案。它基于标准而不是特定的编译器。它回答了原始问题,没有走入任何离题的方向。 - Darryl
3
不使用using namespace std的另一个原因 - Lee Louviere
@Darryl:公平地说,所有早期的答案也是这样做的。 - Lightness Races in Orbit
3
C++11标准规定cstddef应该定义stddef.h所定义的所有内容,包括::size_t。因此,我认为没有理由使用std::size_t代替size_t。请参见“18.2.2:<сstddef>内容与标准C库头文件<stddef.h>相同,以下是更改内容...”,这里没有关于::size_t缺失的内容。 - Eugene Shapovalov
@eugene 答案是特定于 C++03 的。如果需要,可以扩展以涵盖 C++11。其中一个优点是,如果这是目标之一,您的代码将保持符合 C++03。 - Johannes Schaub - litb
@EugeneShapovalov,我对这句话并不信服:如果我们按照你的解释来看,它从未说过应该定义std::size_t!我想即使那个句子仍然需要与[contents]/2一起使用,后者说:“所有库实体[...]均在命名空间std内定义...” - M.M

42

C++标准的第17.4.1.2节第4段声明:

“然而,在C ++标准库中,除了在C中定义为宏的名称外,声明和定义都位于命名空间std的命名空间范围内(3.3.5)。”

这包括在模板的头文件中找到的项目,其中包括定义size_t的。

因此,使用std :: size_t是正确的。


13

你可以通过包含例如<stddef.h>而不是<cstddef>来获取全局命名空间中的size_t。我看不出明显的优势,而这个特性已被弃用。


一些关于负投票的解释会更礼貌。该回答是正确且与主题相关的。 - fizzer
我不知道是谁给你投了反对票。你的观察非常符合原始问题。 - Don Wakefield
我投了你的反对票,主要是因为有一种非废弃的方法可以做到这一点:使用声明,即using std::size_t,而你没有提到这是一个更好的选择。 :-) - cic
5
除非我认为@fizzer是在解释你的C++程序中如何可能出现全局命名空间中的size_t,而不是建议你这样做。 - Don Wakefield
你并没有真正回答这个问题,而是回答了一个相关的问题。 - Lightness Races in Orbit

4
std::size_t n = sizeof( long );

实际上,您还没有问到上述哪些具体做法似乎是不好的。在C++标准中(18.1),size_t是在标准头文件中定义的类型。我建议放弃任何可能从C语言继承的想法和印象。C++是一种独立而不同的语言,最好把它作为这样考虑。它有自己的标准库,所有C++标准库的元素都定义在命名空间std内。然而,在C++程序中使用C标准库的元素是可能的。

我认为包含是一个不好的hack。C++标准规定,头文件的内容与C标准库中相应头文件的内容相同或基于其内容,但在某些情况下,已经应用了更改。换句话说,这不是将C头文件直接复制粘贴到C++头文件中。

size_t不是C++中的内置类型。它是一种类型,用于指定作为sizeof()运算符返回类型使用的整数类型,因为sizeof()的实际返回类型是实现定义的,所以C++标准通过定义size_t来进行统一。

would the following program (with no includes) be expected to compile on all C++ compilers?

size_t foo()
{
    return sizeof( long );
}

C++标准规定(1.4):

库中定义的名称具有命名空间范围(7.3)。通过包含适当的标准库头文件(16.2),C++翻译单元(2.1)可以访问这些名称。

size_t是std命名空间中定义的名称,因此使用该名称的每个程序都应该包含相应的头文件,就像在本例中一样。

接下来,3.7.3章节说:

但是,引用std、std::bad_alloc和std::size_t是非法的,除非通过包含适当的头文件声明了名称。

因此,使用size_t但未包含头文件的程序是非法的。


4

size_t在C++中没有内置。它也不是默认定义的。这段代码在GCC下无法编译:

int main(int argc, char** argv) {
size_t size;
}

话说,size_t是POSIX的一部分,如果您只使用基本的内容,如< cstdlib>,您可能最终会定义它。

你可以认为std::size_t是size_t的C++等效类型。正如Brian所指出的那样,std::用作命名空间,以避免设置不适合所有人的全局变量。这就像std::string一样,也可以在根名称空间中定义。


3
GNU编译器头文件包含以下内容:
typedef long int __PTRDIFF_TYPE__;
typedef unsigned long int __SIZE_TYPE__;
然后,stddef.h 包含以下内容:
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
最后,cstddef 文件包含以下内容:
#include <stddef.h>
namespace std {
using ::ptrdiff_t; using ::size_t;
}
只要您包含了 <cstddef>,就可以使用 size_t 或 std::size_t,因为 size_t 在 std 命名空间之外进行了 typedef,并随后被包含。实际上,您有:
typedef long int ptrdiff_t;
typedef unsigned long int size_t;
namespace std {
using ::ptrdiff_t; using ::size_t;
}

GNU 是这样定义的,那么所有编译器都是这样吗?标准规定必须这样吗? - Michael Dorst

2
我认为这些澄清已经足够明确了。在C++中,std::size_t是有意义的,在C语言中,::size_t也是至少有意义的。
然而,还有一个问题。即是否可以安全地假设 ::size_tstd::size_t 是兼容的?
从纯类型安全的角度来看,除非定义了它们必须相同,否则它们并不一定相同。
我认为很多人都使用类似以下的东西:
----
// 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 ) 
{
  ...
}

在头文件中,你肯定会使用 ::size_t,而在源文件中,你将使用 std::size_t。因此,它们必须是兼容的,否则你将会遇到编译错误。

/Michael S.


2
在没有命名空间的C语言中,::size_t是没有意义的。 - Billy ONeal

2

有时候其他库会定义它们自己的 size_t,例如 boost。std::size_t 表明你肯定要使用 c++ 标准中的 size_t。

size_t 是 c++ 的标准类型,并在命名空间 std 中定义。


这很有道理。您知道 "::size_t" 或 "std::size_t"(或者两者都)是否是语言规范的一部分吗? - jwfearn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接