为什么 shared_ptr<T>::use_count() 返回 long 而不是无符号类型?

25

shared_ptr观察器 20.8.2.2.5 C++14最终草案(n4296)

   long use_count() const noexcept;

返回:与*this共享所有权的shared_ptr对象数量,包括*this本身,如果*this为空,则返回0。

[注意:use_count()不一定高效。—注释结束]


1
我想知道如果计数超过LONG_MAX,定义的行为是什么。 - M.M
3
我猜到那个时候软件已经在其他方面出了问题。 - Ed Heal
2个回答

23
根据此页面。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html

“use_count”的返回类型是有符号的,以避免类似“p.use_count() > -1”被判定为假的陷阱。 参考文献:John Lakos,《大规模 C++ 软件设计》,第9.2.2节,第637页,Addison-Wesley出版社,1996年7月,ISBN 0-201-63362-0。 基本上,这看起来像是一个保姆级别的决策,为大一软件开发人员量身定制。

2
嗯...看起来像是我的第三个要点。 - 6502
2
一个易于使用的界面,他们到底在想什么? - nwp
3
《Lakos书》很棒,可能是影响我C++编程最多的书籍之一。其中一个规则是,在接口中不要使用无符号类型。这不是为了照顾新手级别的软件开发人员而做出的“摆烂决策”,而是有关如何扩展软件开发并确保其可靠性的深度建议。 - janm
请注意,此答案中引用的N1450之后还指出了以下内容:“use_count的长返回类型并不意味着实现应始终使用long作为引用计数。在某些情况下,size_t或其带符号等效项可能是实际使用的更好选择。”这种返回类型的错误选择应该不足为奇,因为N1450还指出:“use_count是作为测试和调试辅助工具而提供的,而不是用于生产代码”。 - jotik
那本书的第9.2.3节写道:“指南:在接口中避免使用long。” - Evg

17
这是因为对于这种计数器,最合适的类型是常规的signed整数,即使此计数器永远不会低于0。
为什么计数器应该是unsigned?它不能变成负数并不是目前语言中unsigned的真正含义,因此这并不是一个有效的借口。
在C++中,unsigned并不意味着“不能为负数的整数”。要理解为什么这个定义根本没有意义,请考虑以下几点:
  • 两个unsigned的差是unsigned
  • unsignedsigned相加的结果是unsigned
  • unsigned值永远不会大于-1
如果您认为unsigned的含义是“非负数”,那么以上任何一点都没有意义。
使用unsigned来表示size_t是一个错误(例如参见为什么size_t是无符号的?),这个错误只有在16位时代被认为值得一用,因为当时多出来的一个比特位被认为可以弥补unsigned类型在C++中这种用法上的错误语义。
不幸的是现在size_t的错误不能被修正(因为向后兼容),但是为什么要在另一个无关的领域重复同样的错误呢?
请注意,可能犯的最大的错误只是选择了unsigned这个名称(考虑到它的实际意义)。如果那种类型被命名为(更恰当的)模数,那么也许使用模数int表示字符串的大小根本就没有任何意义。
名称并不重要,重要的是语义,而unsigned对于计数器或大小来说只是具有错误的语义。

(*) 我个人认为,即使在当时,32767 的大小也不足够好的理由。如果现在 32767 不够用了,那么 65535 很快也不会够用。在我看来,仅仅为了扭曲语义而多一个比特(两倍于原值)是不能接受的代价。

编辑

我发布了一个视频,在其中更详细地讨论了为什么我认为在 C++ 中使用无符号类型作为 size_t 是一个设计错误。

幻灯片可以从 http://raksy.dyndns.org/unsigned.pdf 下载。


10
那是发牢骚,不是答案。你的主张需要有理由才能有意义并对读者有所帮助。 - Ulrich Eckhardt
10
@6502: 首先,Stroustrup有权发表自己的意见,但他是错误的。其次,无论有哪些选项可用,决定早已在很长时间前做出。标准库的大小/计数是无符号的。为什么这个突然变成有符号的确实不清楚。而采用无符号类型来计数/大小与获得额外值域位数无关。 - AnT stands with Russia
6
第三点,无符号类型的本质与支配 C 和 C++ 迭代器语义的开闭范围的性质一致。它一直存在于语言的核心,并且不可避免。这不是某个人的决定,而是世界的运作方式。因此,最初的错误实际上是推动 有符号 类型 - 甚至比 Stroustrup 更早地犯了这个错误。有符号类型属于应用程序特定领域。编程本身是无符号、无符号和无符号的,只有极少数情况下才会使用有符号类型。 - AnT stands with Russia
3
@janm:很少有情况需要单个数组(由单个字节组成)占用一半以上的地址空间。甚至更少的情况下,您无法承担使用多精度整数来处理该大小(例如long)。将这些情况用于弯曲所有其他用例的规则,从而使未来的程序员因此而遭受愚蠢的错误,我认为这是一个值得质疑的选择。当然,如果有另一种整数类型用于非负整数(具有正确的语义),那就太好了...但是unsigned并不是那种类型。 - 6502
6
在编程经验超过十年后,我不再在数学/逻辑运算(如比较)中使用“unsigned”类型。我仅在位操作的情况下使用“unsigned”。这样做可以避免由于自动将有符号值转换为无符号值而导致“-1”变成非常大的值等问题。 - Nawaz
显示剩余22条评论

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