【问题标题】:Why is it a good idea for (C++) types to be regular?为什么 (C++) 类型是常规类型是个好主意?
【发布时间】:2020-07-17 19:12:30
【问题描述】:

(这个问题源于this 有关流迭代器的更具体的问题。)

A 类型是 said [Stepanov, McJones] 是 Regular 如果:

  • 它是平等可比的
  • 它是可赋值的(从该类型的其他值)
  • 它是可破坏的
  • 它是默认可构造的(即可以不带参数构造)
  • 它的值有一个(默认)总排序

(还有一些关于“底层类型”的措辞,我不太明白。)

一些/许多人声称,在设计类型时 - 例如对于 C++ 的标准库 - 努力使这些类型常规化是值得甚至重要的,可能会忽略总顺序要求。有人提到格言:

ints 那样做。

确实,int 类型满足所有这些要求。但是,默认可构造类型在构造时会保存某种空值、无效值或垃圾值 - ints 确实如此。另一种方法是在构造时要求初始化(在销毁时取消初始化),以便对象的生命周期与其生存时间相对应。

为了对比这两种方法,可以考虑一个 T-pointer 类型和一个 T-reference 或 T-reference-wrapper 类型。指针基本上是规则的(排序假定一个线性地址空间),并且有需要注意的nullptr;引用实际上是一个指针——但你不能只构造一个无引用或垃圾引用。现在,指针可能有它们的位置,但我们更喜欢使用引用(或者可能是可分配的引用包装器)。

那么,为什么我们应该更喜欢设计(作为库作者)和使用常规类型?或者至少,我们为什么要在这么多情况下更喜欢它们?

【问题讨论】:

  • 我不明白这个问题。您是否在问为什么默认初始化对象应该包含垃圾数据?我想没有人这么说。事实上,标准库中的大多数对象都有一个明确定义的默认值(std::vectorstd::string、除std::array 之外的所有其他容器)。
  • @Ayxan:不,我不是这个意思。见最后一句的编辑。此外,您的前两个示例值得讨论:std::vector 是非常有意义的默认构造,因为它具有“合法”的空状态。这有点像std::string 的情况;虽然我个人不允许字符串类的默认构造函数:你想要一个字符串?说它包含什么。如果您想要一个空字符串,请这样说;因为字符串不像你插入的字符序列。

标签: c++ types idioms regular-type


【解决方案1】:

我怀疑这是最重要的答案,但您可以提出“没有未初始化的状态”/“没有垃圾值”是一个不适合移动分配的原则:在你离开你的价值之后,并拿走它的资源——它还处于什么状态?它距离默认构造它不是很远(除非移动分配基于某种交换;但是 - 你可以查看移动构造)。

反驳是:“好吧,所以我们不要让这种类型移动可分配,只有移动可破坏”;不幸的是 - C++ 在 2000 年代的某个时候决定采用非破坏性的动作。另请参阅@HowardHinnant 的这个问题和答案:

Why does C++ move semantics leave the source constructed?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 2015-08-28
    • 1970-01-01
    • 2015-02-20
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多