【问题标题】:What are the arguments against using size_t?反对使用 size_t 的论据是什么?
【发布时间】:2011-09-27 04:52:22
【问题描述】:

我有一个这样的 API,

class IoType {
......
    StatusType writeBytes(......, size_t& bytesWritten);
    StatusType writeObjects(......, size_t& objsWritten);
};

我尊敬的团队的一位资深成员似乎对 size_t 类型有问题,并建议我使用 C99 类型。我知道这听起来很愚蠢,但我一直认为像 uint32_t 和 uint64_t 这样的 c99 类型看起来很难看。我确实使用它们,但仅在真正需要时使用,例如当我需要序列化/反序列化结构时,我确实想具体说明我的数据成员的大小。

反对使用 size_t 的理由是什么?我知道它不是真正的类型,但如果我确定 32 位整数对我来说就足够了,并且大小类型似乎适合字节数或对象数等。

【问题讨论】:

  • “团队的高级成员”是个白痴。
  • 你问原因了吗?
  • @iammilind,还没有。我在考虑是否值得提出。
  • 我有高级成员告诉我 shared_ptrs 切片 (stackoverflow.com/questions/3305753/shared-ptr-and-slicing) 这真的很令人沮丧,再加上他有一个 alpha 极客态度,并没有争论为什么要提升文档有误。

标签: c++ types c99


【解决方案1】:

当您处理任何类型的序列化(二进制文件、网络等)时,请使用精确大小的类型,例如 uint32_t。每当您处理内存中对象的大小时,请使用size_t — 这就是它的用途。所有处理对象大小的函数,如mallocstrlensizeof 运算符都为size_t

如果您正确使用size_t,您的程序将具有最大的可移植性,并且不会在不需要的平台上浪费时间和内存。在 32 位平台上,size_t 将是 32 位 — 如果您改为使用 uint64_t,则会浪费时间和空间。相反,在 64 位平台上,size_t 将是 64 位 — 如果您改为使用 uint32_t,如果您的程序不得不处理一块大于 4 GB 的内存。

【讨论】:

  • 我同意你的看法。问题在于,除了将 size_t 用于内存大小或数组大小或字符串大小等之外。我将它用于字节数或对象数,而不完全是其预期用途。这是一个好习惯吗?或者至少可以接受吗?
  • @grokus:字节数非常适合size_t。对于对象的数量,它可以采用任何一种方式:您可以使用 size_t,或者如果您认为没有任何方法可以拥有超过 40 亿个对象,则可以使用普通的旧 int
  • @Adam: 关于“40 亿”:int 正式只保证 16 位范围 -32767 到 +32767。显然缺少底部值是因为也不能保证二进制补码表示。
  • @Alf:是的,这是真的。如果您想移植到具有 16 位 ints 的系统,那么您需要更加小心,但是如今编写的需要与 16 位兼容的软件很少。
【解决方案2】:

我想不出在不需要序列化值的上下文中使用 size_t 有什么问题。此外,正确使用 size_t 将提高代码在 32 位和 64 位模式下的安全性/可移植性。

【讨论】:

  • 我要补充一点的是,我们是一家初创公司,并且在 64 位平台上进行开发,所以不存在 32 到 64 位的问题。
  • 为什么要向后看? size_t 也将在明天的 128 位系统上“正常工作”。这甚至算不上千钧一发。就像我说的,你的“高级”团队成员是个白痴。
【解决方案3】:

嗯,用可移植性较差的 C99 固定大小或最小大小无符号类型替换 size_t(最大可移植的东西)不是一个好主意。

另一方面,您可以通过使用签名的ptrdiff_t 类型来避免很多技术问题(浪费时间)。标准库使用无符号类型只是出于历史原因。它在当时是有意义的,甚至在今天在 16 位架构上也是如此,但通常它只是麻烦和冗长。

但是,进行该更改需要一些支持,特别是 a general size function 将数组或容器大小返回为 ptrdiff_t


现在,关于您的函数签名
    StatusType writeBytes(......, size_t& bytesWritten);

强制调用代码选择写入字节数的类型。

然后,强制使用无符号类型size_t,很容易引入错误,例如通过检查它是否小于或大于某个计算量。

一个怪诞的例子:std::string("ah").length() < -5 保证true

所以,做那个……

    Size writeBytes(......);

或者,如果您不想使用异常,

    Size writeBytes(......, StatusType& status );

可以将可能的状态枚举为无符号类型或其他类型,因为对状态值的唯一操作将是相等检查并且可能作为键。

【讨论】:

  • 如果您在 32 位系统上有一个 3 GB 的对象怎么办?
  • @Keith:那你必须做你该做的,对待它非常特别。 :-) 或者更好,只是不要那样做。它可能会在 Windows 中造成一些严重的垃圾(当您从 2G 增加可用地址空间时),我怀疑 *nix 也是如此。
猜你喜欢
  • 2011-11-07
  • 2018-09-04
  • 2017-11-18
  • 2013-06-16
  • 1970-01-01
  • 2012-04-27
  • 1970-01-01
  • 2015-04-25
  • 1970-01-01
相关资源
最近更新 更多