首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++代码中仍然有理由使用‘in’吗?

在C++代码中仍然有理由使用‘in’吗?
EN

Stack Overflow用户
提问于 2018-02-11 07:38:36
回答 8查看 25.1K关注 0票数 186

例如,许多样式指南,如Google,建议在索引数组时使用int作为默认整数。随着64位平台的兴起,在大多数情况下,int只有32位,这并不是平台的自然宽度。因此,除了简单的选择之外,我看不出有什么理由保留这一选择。我们清楚地看到,在编译以下代码时:

代码语言:javascript
复制
double get(const double* p, int k) {
  return p[k];
}

它被编译成

代码语言:javascript
复制
movslq %esi, %rsi
vmovsd (%rdi,%rsi,8), %xmm0
ret

其中,第一条指令将32位整数提升为64位整数。

如果代码被转换为

代码语言:javascript
复制
double get(const double* p, std::ptrdiff_t k) {
  return p[k];
}

生成的程序集现在

代码语言:javascript
复制
vmovsd (%rdi,%rsi,8), %xmm0
ret

这清楚地表明,与使用std::ptrdiff_t相比使用int,CPU更像是在家里。许多C++用户已经迁移到std::size_t,但我不想使用无符号整数,除非我真的需要模2^n行为。

在大多数情况下,使用int不会影响性能,因为未定义的行为或有符号的整数溢出允许编译器在处理索引的循环中内部将任何int提升到std::ptrdiff_t,但我们从上面可以清楚地看到,编译器对int感到不自在。此外,在64位平台上使用std::ptrdiff_t会减少溢出的可能性,因为我看到越来越多的人在处理比2^31 - 1更大的整数时,越来越多的人被int溢出所困。

据我所见,使int独立的唯一原因似乎是,像5这样的文字都是int,但如果我们将std::ptrdiff_t作为默认整数移到std::ptrdiff_t中,它可能不会造成任何问题。

我即将将std::ptrdiff_t作为在我的小公司中编写的所有代码的事实上的标准整数。为什么这可能是个糟糕的选择呢?

PS:我同意std::ptrdiff_t这个名字很难看的事实,这也是为什么我将其命名为il::int_t的原因,后者看起来要好一些。

PS:因为我知道很多人会建议我使用std::size_t作为默认整数,我真的想明确一点,我不想使用无符号整数作为我的默认整数。在STL中使用std::size_t作为默认整数是一个错误,Bjarne和视频https://www.youtube.com/watch?v=Puio5dly9N8中的标准委员会在时间42:38和1:02:50承认了这一点。

PS:就性能而言,在我所知道的任何64位平台上,+__、-*都会以同样的方式编译intstd::ptrdiff_t__。所以速度没有差别。如果用编译时常数除以,速度是相同的.只有当您在不了解a/b的情况下除以b时,在64位平台上使用32位整数才会给您带来一点性能上的优势。但这种情况非常罕见,因为我不认为这是离开std::ptrdiff_t__的一种选择。当我们处理矢量化代码时,这里有一个明显的区别,而且越小越好,但这是另一回事,没有理由坚持使用int__。在这些情况下,我建议使用固定大小的C++类型。

EN

回答 8

Stack Overflow用户

发布于 2018-02-11 10:37:34

对C++核心指南进行了讨论,讨论了如何使用:

https://github.com/isocpp/CppCoreGuidelines/pull/1115

赫伯萨特写道,gsl::index将被添加(在未来可能是std::index),这将被定义为ptrdiff_t

hsutter于2017年12月26日发表评论 (感谢许多WG21专家对本说明的评论和反馈。) 向GSL中添加以下类型的冒险者 namespace gsl { using index = ptrdiff_t; } 并为所有容器索引/下标/大小推荐gsl::index基本原理 准则建议对下标/索引使用有符号类型。见ES.100至ES.107。C++已经为数组下标使用有符号整数。 我们希望能够教人们编写“新的干净的现代代码”,这是简单、自然、无警告的高警告级别,而不是让我们写一个关于简单代码的“陷阱”脚注。 如果我们没有像index这样与intauto竞争的可采用的简短词汇,人们仍然会使用intauto来获取他们的bug。例如,他们将编写for(int i=0; i<v.size(); ++i)for(auto i=0; i<v.size(); ++i),它们在广泛使用的平台上有32位大小的bug,而for(auto i=v.size()-1; i>=0; ++i)则无法工作。我不认为我们可以用一张严肃的脸来教for(ptrdiff_t i = ...,或者说人们会接受它。 如果我们有一个饱和的算术类型,我们可以使用它。否则,最好的选择是ptrdiff_t,它几乎具有饱和算术无符号类型的所有优点,除了ptrdiff_t仍然使普适循环样式的for(ptrdiff_t i=0; i<v.size(); ++i)i<v.size()上发出符号/无符号的不匹配(对于i!=v.size()也是如此)。(如果未来的STL将其size_type更改为要签名,则即使最后一个缺点也会消失。) 然而,尝试教人们常规地写for (ptrdiff_t i = ... ; ... ; ...)是没有希望的(也是令人尴尬的)。(即使是指南目前也只在一个地方使用它,这是一个与indexing.) Therefore we should providegsl::index(which can later be proposed for consideration asstd::index) as a typedef forptrdiff_t, so we can hopefully (and not embarrassingly) teach people to routinely write for(index i=.无关的“坏”示例;.;...). **Why not just tell people to write** **ptrdiff_t****?** Because we believe it would be embarrassing to tell people that's what you have to do in C++, and even if we did people won't do it. Writingptrdiff_tis too ugly and unadoptable compared toautoandint. The point of adding the nameindex`是为了使使用正确大小的符号类型变得尽可能简单和有吸引力。

编辑: Herb Sutter的更多理由

ptrdiff_t 够大吗?是的。标准容器已经不需要有比ptrdiff_t表示的元素更多的元素,因为减去两个迭代器必须适合在一个difference_type中。 但是,如果我有一个内建数组( ptrdiff_t char byte ),它比内存地址空间的一半还大,所以有比 ptrdiff_t**?**是的更多的元素,那么就足够大了。C++已经为数组下标使用有符号整数。因此,使用index作为大多数用途(包括所有内置数组)的默认选项。(如果您确实遇到了数组或类似数组的类型这种非常罕见的情况,即大于一半的地址空间,并且其元素是sizeof(1),而且您要小心避免截断问题,那么继续使用size_t作为索引,只用于这个非常特殊的容器中。这样的野兽在实践中是非常罕见的,当它们真的出现时,通常不会被用户代码直接编入索引。例如,它们通常出现在接收系统分配的内存管理器中,并将用户使用的单个较小的分配打包出来,或者出现在提供自己接口的MPEG或类似的内存管理器中;在这两种情况下,size_t只应该在内存管理器或MPEG类实现中被内部使用。)

票数 106
EN

Stack Overflow用户

发布于 2018-02-11 17:49:47

我从一个老计时器的角度来看这个问题(C++前).人们早在当时就知道,int是该平台的本土化词汇,很可能提供最好的性能。

如果你需要更大的东西,那么你就会使用它并付出性能上的代价。如果您需要更小的东西(有限的内存,或对固定大小的特定需求),那么同样的事情。否则使用int。是的,如果您的值在一个目标平台上int可以容纳它的范围内,而int在另一个目标平台上不能容纳它。然后,我们有了编译时大小的特定定义(在它们标准化之前,我们制定了自己的定义)。

但是现在,处理器和编译器要复杂得多,这些规则不那么容易应用。你的选择对未来某个未知平台或编译器的性能影响也很难预测.我们如何真正知道,例如,在任何特定的未来目标上,uint64_t会比uint32_t表现得更好或更差?除非你是处理器/编译器专家,否则你不会.

所以..。也许这是过时的,但是除非我正在为Arduino这样的受限环境编写代码,否则我仍然使用int作为通用值,我知道对于我正在编写的应用程序的所有合理目标来说,这些值都在int大小之内。然后编译器就会从那里..。现在,这通常意味着32位签名。即使假定16位是最小整数大小,它也涵盖了大多数用例。而大于数字的用例很容易识别并使用适当的类型来处理。

票数 37
EN

Stack Overflow用户

发布于 2018-02-11 10:28:16

大多数程序不会在几个CPU周期的边缘生存和死亡,而且int非常容易编写。但是,如果您对性能敏感,我建议使用在<cstdint>中定义的固定宽度整数类型,例如int32_tuint64_t。它们的好处是它们在被签名或未签名方面的行为非常清晰,以及它们在内存中的大小。此标头还包括快速变体(如int_fast32_t ),它至少具有指定的大小,但如果有助于性能,则可能更多。

票数 20
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48729384

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档