何时使用 std::size_t?

发布于 2024-08-16 13:58:31 字数 314 浏览 8 评论 0原文

我只是想知道我应该使用 std::size_t 进行循环和其他内容而不是 int 吗? 例如:

#include <cstdint>

int main()
{
    for (std::size_t i = 0; i < 10; ++i) {
        // std::size_t OK here? Or should I use, say, unsigned int instead?
    }
}

一般来说,何时使用 std::size_t 的最佳实践是什么?

I'm just wondering should I use std::size_t for loops and stuff instead of int?
For instance:

#include <cstdint>

int main()
{
    for (std::size_t i = 0; i < 10; ++i) {
        // std::size_t OK here? Or should I use, say, unsigned int instead?
    }
}

In general, what is the best practice regarding when to use std::size_t?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

没有心的人 2024-08-23 13:58:31

一个好的经验法则是,您需要在循环条件中与自然是 std::size_t 本身的内容进行比较。

std::size_t 是任何 sizeof 表达式的类型,并且 as 保证能够表达 C++ 中任何对象(包括任何数组)的最大大小。通过扩展,它还保证对于任何数组索引都足够大,因此它是数组上按索引循环的自然类型。

如果您只是计算一个数字,那么使用保存该数字的变量类型或 intunsigned int 可能更自然(如果很大的话)足够),因为这些应该是机器的自然尺寸。

A good rule of thumb is for anything that you need to compare in the loop condition against something that is naturally a std::size_t itself.

std::size_t is the type of any sizeof expression and as is guaranteed to be able to express the maximum size of any object (including any array) in C++. By extension it is also guaranteed to be big enough for any array index so it is a natural type for a loop by index over an array.

If you are just counting up to a number then it may be more natural to use either the type of the variable that holds that number or an int or unsigned int (if large enough) as these should be a natural size for the machine.

携余温的黄昏 2024-08-23 13:58:31

size_tsizeof 运算符的结果类型。

使用 size_t 作为对数组中的大小或索引进行建模的变量。 size_t 传达语义:您立即知道它代表字节大小或索引,而不仅仅是另一个整数。

此外,使用 size_t 表示字节大小有助于使代码可移植。

size_t is the result type of the sizeof operator.

Use size_t for variables that model size or index in an array. size_t conveys semantics: you immediately know it represents a size in bytes or an index, rather than just another integer.

Also, using size_t to represent a size in bytes helps making the code portable.

苦行僧 2024-08-23 13:58:31

size_t 类型旨在指定某些内容的大小,因此使用它是很自然的,例如,获取字符串的长度,然后处理每个字符:

for (size_t i = 0, max = strlen (str); i < max; i++)
    doSomethingWith (str[i]);

当然必须注意边界条件,因为它是无符号类型。顶端的边界通常并不那么重要,因为最大值通常很大(尽管有可能到达那里)。大多数人只是使用 int 来处理这类事情,因为他们很少有足够大的结构或数组来超出该 int 的容量。

但请注意以下情况:

for (size_t i = strlen (str) - 1; i >= 0; i--)

由于无符号值的包装行为,这将导致无限循环(尽管我已经看到编译器对此发出警告)。这也可以通过以下方式来缓解(稍微难以理解,但至少不受包装问题的影响):

for (size_t i = strlen (str); i-- > 0; )

通过将减量转移到连续条件的检查后副作用中,这会检查值 的连续性在递减之前,但仍然在循环内使用递减后的值(这就是循环从 len .. 1 而不是 len-1 .. 0 运行的原因)。

The size_t type is meant to specify the size of something so it's natural to use it, for example, getting the length of a string and then processing each character:

for (size_t i = 0, max = strlen (str); i < max; i++)
    doSomethingWith (str[i]);

You do have to watch out for boundary conditions of course, since it's an unsigned type. The boundary at the top end is not usually that important since the maximum is usually large (though it is possible to get there). Most people just use an int for that sort of thing because they rarely have structures or arrays that get big enough to exceed the capacity of that int.

But watch out for things like:

for (size_t i = strlen (str) - 1; i >= 0; i--)

which will cause an infinite loop due to the wrapping behaviour of unsigned values (although I've seen compilers warn against this). This can also be alleviated by the (slightly harder to understand but at least immune to wrapping problems):

for (size_t i = strlen (str); i-- > 0; )

By shifting the decrement into a post-check side-effect of the continuation condition, this does the check for continuation on the value before decrement, but still uses the decremented value inside the loop (which is why the loop runs from len .. 1 rather than len-1 .. 0).

清音悠歌 2024-08-23 13:58:31

根据定义,size_tsizeof 运算符的结果。 size_t 的创建是为了引用尺寸。

你做某事的次数(在你的例子中是 10 次)与大小无关,那么为什么要使用 size_t 呢? intunsigned int 应该没问题。

当然,这也与您在循环内使用 i 执行的操作有关。例如,如果将其传递给采用 unsigned int 的函数,请选择 unsigned int

无论如何,我建议避免隐式类型转换。 明确所有类型转换。

By definition, size_t is the result of the sizeof operator. size_t was created to refer to sizes.

The number of times you do something (10, in your example) is not about sizes, so why use size_t? int, or unsigned int, should be ok.

Of course it is also relevant what you do with i inside the loop. If you pass it to a function which takes an unsigned int, for example, pick unsigned int.

In any case, I recommend to avoid implicit type conversions. Make all type conversions explicit.

不可一世的女人 2024-08-23 13:58:31

简短的回答:

几乎从不。使用签名版本 ptrdiff_t 或非标准 ssize_t。使用函数 std::ssize 而不是 std::size

长答案:

每当您需要在 32 位系统上拥有大于 2GB 的 char 向量时。在所有其他用例中,使用有符号类型比使用无符号类型安全得多。

例如:

std::vector<A> data;
[...]
// calculate the index that should be used;
size_t i = calc_index(param1, param2);
// doing calculations close to the underflow of an integer is already dangerous

// do some bounds checking
if( i - 1 < 0 ) {
    // always false, because 0-1 on unsigned creates an underflow
    return LEFT_BORDER;
} else if( i >= data.size() - 1 ) {
    // if i already had an underflow, this becomes true
    return RIGHT_BORDER;
}

// now you have a bug that is very hard to track, because you never 
// get an exception or anything anymore, to detect that you actually 
// return the false border case.

return calc_something(data[i-1], data[i], data[i+1]);

size_t 的有符号等价物是 ptrdiff_t,而不是 int。但在大多数情况下使用 int 仍然比 size_t 要好得多。 ptrdiff_t 在 32 位和 64 位系统上为 long

这意味着每当与 std::containers 交互时,您总是必须在 size_t 之间进行转换,这不太美观。但在一次本地会议上,c++ 的作者提到用无符号 size_t 设计 std::vector 是一个错误。

如果您的编译器向您发出有关从 ptrdiff_t 到 size_t 的隐式转换的警告,您可以使用构造函数语法将其显式显示:

calc_something(data[size_t(i-1)], data[size_t(i)], data[size_t(i+1)]);

如果只想迭代集合而不进行边界检查,请使用基于范围的 for:

for(const auto& d : data) {
    [...]
}

这里是 Bjarne Stroustrup(C++ 作者)的一些话走向原生

对于某些人来说,这个签名/未签名的设计错误STL 有足够的理由不使用 std::vector,而是使用自己的实现。

short answer:

Almost never. Use signed version ptrdiff_t or non-standard ssize_t. Use function std::ssize instead of std::size.

long answer:

Whenever you need to have a vector of char bigger that 2gb on a 32 bit system. In every other use case, using a signed type is much safer than using an unsigned type.

example:

std::vector<A> data;
[...]
// calculate the index that should be used;
size_t i = calc_index(param1, param2);
// doing calculations close to the underflow of an integer is already dangerous

// do some bounds checking
if( i - 1 < 0 ) {
    // always false, because 0-1 on unsigned creates an underflow
    return LEFT_BORDER;
} else if( i >= data.size() - 1 ) {
    // if i already had an underflow, this becomes true
    return RIGHT_BORDER;
}

// now you have a bug that is very hard to track, because you never 
// get an exception or anything anymore, to detect that you actually 
// return the false border case.

return calc_something(data[i-1], data[i], data[i+1]);

The signed equivalent of size_t is ptrdiff_t, not int. But using int is still much better in most cases than size_t. ptrdiff_t is long on 32 and 64 bit systems.

This means that you always have to convert to and from size_t whenever you interact with a std::containers, which not very beautiful. But on a going native conference the authors of c++ mentioned that designing std::vector with an unsigned size_t was a mistake.

If your compiler gives you warnings on implicit conversions from ptrdiff_t to size_t, you can make it explicit with constructor syntax:

calc_something(data[size_t(i-1)], data[size_t(i)], data[size_t(i+1)]);

if just want to iterate a collection, without bounds cheking, use range based for:

for(const auto& d : data) {
    [...]
}

here some words from Bjarne Stroustrup (C++ author) at going native

For some people this signed/unsigned design error in the STL is reason enough, to not use the std::vector, but instead an own implementation.

巾帼英雄 2024-08-23 13:58:31

size_t 是一种非常易读的方式来指定项目的大小维度 - 字符串的长度、指针占用的字节数等。
它也可以跨平台移植 - 您会发现 64 位和 32 位都可以很好地处理系统函数和 size_t - 这是 unsigned int 可能不会做的事情(例如,什么时候应该使用无符号长

size_t is a very readable way to specify the size dimension of an item - length of a string, amount of bytes a pointer takes, etc.
It's also portable across platforms - you'll find that 64bit and 32bit both behave nicely with system functions and size_t - something that unsigned int might not do (e.g. when should you use unsigned long

情独悲 2024-08-23 13:58:31

使用 std::size_t 来索引/计数 C 样式数组。

对于 STL 容器,您将拥有(例如)vector::size_type,它应用于向量元素的索引和计数。

在实践中,它们通常都是无符号整数,但这并不能保证,特别是在使用自定义分配器时。

Use std::size_t for indexing/counting C-style arrays.

For STL containers, you'll have (for example) vector<int>::size_type, which should be used for indexing and counting vector elements.

In practice, they are usually both unsigned ints, but it isn't guaranteed, especially when using custom allocators.

擦肩而过的背影 2024-08-23 13:58:31

很快,大多数计算机将采用 64 位架构,并配备 64 位操作系统,运行在包含数十亿个元素的容器上运行的程序。那么你必须使用size_t而不是int作为循环索引,否则你的索引将在2^处环绕第 32 个元素,在 32 位和 64 位系统上均如此。

为未来做好准备!

Soon most computers will be 64-bit architectures with 64-bit OS:es running programs operating on containers of billions of elements. Then you must use size_t instead of int as loop index, otherwise your index will wrap around at the 2^32:th element, on both 32- and 64-bit systems.

Prepare for the future!

且行且努力 2024-08-23 13:58:31

size_t 由各种库返回,以指示该容器的大小非零。当你回来时你使用它:0

但是,在上面的示例中,在 size_t 上循环是一个潜在的错误。请考虑以下事项:

for (size_t i = thing.size(); i >= 0; --i) {
  // this will never terminate because size_t is a typedef for
  // unsigned int which can not be negative by definition
  // therefore i will always be >= 0
  printf("the never ending story. la la la la");
}

使用无符号整数有可能产生这些类型的微妙问题。因此,恕我直言,我更喜欢仅在与需要它的容器/类型交互时才使用 size_t 。

size_t is returned by various libraries to indicate that the size of that container is non-zero. You use it when you get once back :0

However, in the your example above looping on a size_t is a potential bug. Consider the following:

for (size_t i = thing.size(); i >= 0; --i) {
  // this will never terminate because size_t is a typedef for
  // unsigned int which can not be negative by definition
  // therefore i will always be >= 0
  printf("the never ending story. la la la la");
}

the use of unsigned integers has the potential to create these types of subtle issues. Therefore imho I prefer to use size_t only when I interact with containers/types that require it.

空袭的梦i 2024-08-23 13:58:31

使用 size_t 时请注意以下表达式

size_t i = containner.find("mytoken");
size_t x = 99;
if (i-x>-1 && i+x < containner.size()) {
    cout << containner[i-x] << " " << containner[i+x] << endl;
}

无论 x 的值是什么,if 表达式中都会得到 false。
我花了几天时间才意识到这一点(代码太简单了,我没有做单元测试),尽管只花了几分钟就找出了问题的根源。不确定是进行强制转换还是使用零更好。

if ((int)(i-x) > -1 or (i-x) >= 0)

两种方法都应该有效。这是我的测试运行

size_t i = 5;
cerr << "i-7=" << i-7 << " (int)(i-7)=" << (int)(i-7) << endl;

输出: i-7=18446744073709551614 (int)(i-7)=-2

我想听听其他人的评论。

When using size_t be careful with the following expression

size_t i = containner.find("mytoken");
size_t x = 99;
if (i-x>-1 && i+x < containner.size()) {
    cout << containner[i-x] << " " << containner[i+x] << endl;
}

You will get false in the if expression regardless of what value you have for x.
It took me several days to realize this (the code is so simple that I did not do unit test), although it only take a few minutes to figure the source of the problem. Not sure it is better to do a cast or use zero.

if ((int)(i-x) > -1 or (i-x) >= 0)

Both ways should work. Here is my test run

size_t i = 5;
cerr << "i-7=" << i-7 << " (int)(i-7)=" << (int)(i-7) << endl;

The output: i-7=18446744073709551614 (int)(i-7)=-2

I would like other's comments.

_蜘蛛 2024-08-23 13:58:31

通常最好不要在循环中使用 size_t。例如,

vector<int> a = {1,2,3,4};
for (size_t i=0; i<a.size(); i++) {
    std::cout << a[i] << std::endl;
}
size_t n = a.size();
for (size_t i=n-1; i>=0; i--) {
    std::cout << a[i] << std::endl;
}

第一个循环就可以了。但对于第二个循环:
当 i=0 时,i-- 的结果将为 ULLONG_MAX(假设 size_t = unsigned long long),这不是您想要的循环结果。
此外,如果 a 为空,则 n=0 且 n-1=ULLONG_MAX 这也不好。

It is often better not to use size_t in a loop. For example,

vector<int> a = {1,2,3,4};
for (size_t i=0; i<a.size(); i++) {
    std::cout << a[i] << std::endl;
}
size_t n = a.size();
for (size_t i=n-1; i>=0; i--) {
    std::cout << a[i] << std::endl;
}

The first loop is ok. But for the second loop:
When i=0, the result of i-- will be ULLONG_MAX (assuming size_t = unsigned long long), which is not what you want in a loop.
Moreover, if a is empty then n=0 and n-1=ULLONG_MAX which is not good either.

月野兔 2024-08-23 13:58:31

size_t 是一种无符号类型,可以容纳架构的最大整数值,因此可以防止由于符号而导致的整数溢出(有符号 int 0x7FFFFFFF 加 1 会得到 - 1) 或短大小(无符号短整型 0xFFFF 加 1 将得到 0)。

主要用于数组索引/循环/地址运算等。像 memset() 之类的函数仅接受 size_t ,因为理论上您可能有一个大小为 2^32-1 的内存块(在32位平台)。

对于如此简单的循环,不必费心,只需使用 int 即可。

size_t is an unsigned type that can hold maximum integer value for your architecture, so it is protected from integer overflows due to sign (signed int 0x7FFFFFFF incremented by 1 will give you -1) or short size (unsigned short int 0xFFFF incremented by 1 will give you 0).

It is mainly used in array indexing/loops/address arithmetic and so on. Functions like memset() and alike accept size_t only, because theoretically you may have a block of memory of size 2^32-1 (on 32bit platform).

For such simple loops don't bother and use just int.

悲喜皆因你 2024-08-23 13:58:31

我一直在努力理解什么以及何时使用它。但 size_t 只是一个无符号整数数据类型,在各种头文件中定义,例如 、< ;time.h>、 等。

它用于表示对象的大小(以字节为单位),因此它被 sizeof 运算符用作返回类型。允许的最大大小取决于编译器;如果编译器是 32 位,那么它只是 unsigned int 的 typedef(别名),但如果编译器是 64 位,那么它将是 unsigned long long 的 typedef。 size_t 数据类型永远不会为负(不包括 ssize_t)
因此,许多 C 库函数(例如 malloc、memcpy 和 strlen)将其参数和返回类型声明为 size_t

/ Declaration of various standard library functions.
  
// Here argument of 'n' refers to maximum blocks that can be
// allocated which is guaranteed to be non-negative.
void *malloc(size_t n);
  
// While copying 'n' bytes from 's2' to 's1'
// n must be non-negative integer.
void *memcpy(void *s1, void const *s2, size_t n);
  
// the size of any string or `std::vector<char> st;` will always be at least 0.
size_t strlen(char const *s);

size_t 或任何无符号类型都可能被视为用作循环变量,因为循环变量通常大于或等于 0。

I have been struggling myself with understanding what and when to use it. But size_t is just an unsigned integral data type which is defined in various header files such as <stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, <time.h>, <wchar.h> etc.

It is used to represent the size of objects in bytes hence it's used as the return type by the sizeof operator. The maximum permissible size is dependent on the compiler; if the compiler is 32 bit then it is simply a typedef (alias) for unsigned int but if the compiler is 64 bit then it would be a typedef for unsigned long long. The size_t data type is never negative(excluding ssize_t)
Therefore many C library functions like malloc, memcpy and strlen declare their arguments and return type as size_t.

/ Declaration of various standard library functions.
  
// Here argument of 'n' refers to maximum blocks that can be
// allocated which is guaranteed to be non-negative.
void *malloc(size_t n);
  
// While copying 'n' bytes from 's2' to 's1'
// n must be non-negative integer.
void *memcpy(void *s1, void const *s2, size_t n);
  
// the size of any string or `std::vector<char> st;` will always be at least 0.
size_t strlen(char const *s);

size_t or any unsigned type might be seen used as loop variable as loop variables are typically greater than or equal to 0.

萝莉病 2024-08-23 13:58:31

size_t 是无符号整数类型,可以表示系统上最大的整数。
仅当您需要非常大的数组、矩阵等时才使用它。

某些函数返回 size_t,如果您尝试进行比较,编译器会警告您。

通过使用适当的有符号/无符号数据类型或简单地进行快速破解来避免这种情况。

size_t is an unsigned integral type, that can represent the largest integer on you system.
Only use it if you need very large arrays,matrices etc.

Some functions return an size_t and your compiler will warn you if you try to do comparisons.

Avoid that by using a the appropriate signed/unsigned datatype or simply typecast for a fast hack.

莫言歌 2024-08-23 13:58:31

size_t 是无符号整数。所以只要你想要 unsigned int 就可以使用它。

当我想指定数组的大小、计数器等时我使用它......

void * operator new (size_t size); is a good use of it.

size_t is unsigned int. so whenever you want unsigned int you can use it.

I use it when i want to specify size of the array , counter ect...

void * operator new (size_t size); is a good use of it.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文