不幸的是,就像Going Native 2013 的所有会谈一样,它受到非常紧迫的时间安排的限制。不过,对我们来说幸运的是,Sean Parent 去年在 C++Now 上进行了更彻底的演讲,名为Value Semantics and Concepts-based Polymorphism。它涵盖了相同的材料,并且可能会回答您的问题。无论如何,我会尽力解释......
简介
一个类型可以有两种类型的语义:
关于两者有何不同以及何时一个比另一个更可取,可以继续写很多页。让我们简单地说,使用值类型的代码更容易推理。
也就是说,值类型的实例在任何时候都不会发生任何不可预测的事情——引用类型无法保证这一点,因为被引用的值在你的代码的其他持有引用的部分之间共享给它。
换句话说:引用类型的可预测性较差,因为它们可以被一段遥远的代码更改。例如,您调用的函数可能会更改从您下方引用的值。或者,更糟糕的是,如果涉及线程,则引用类型可能随时被另一个碰巧对引用的值进行操作的线程更改。出于这个原因,Sean Parent 声明shared_ptr 与全局变量一样好,当涉及到能够对使用它的代码进行推理时。
说了这么多,我们应该准备好回答手头的问题了。
问答
对于值类型T,为什么shared_ptr<const T> 行为类似于值类型,即使它是指针类型?
因为我们无法对指向的const T 进行更改,所以关于指针/引用类型难以预测的所有内容不再适用。我们不再需要担心 T 被意外更改,因为它是一个 const 值类型。
如果我们确实想对 T 进行更改,我们将不得不制作一份副本,让持有 shared_ptr<const T> 的其他人不受我们的行为影响。此外,甚至可以使用称为 Copy-on-write 的机制将副本隐藏在值类型中,这似乎是 Sean Parent 最终所做的。
我想我已经像 Sean Parent 一样回答了这个问题(并且在链接的 C++Now 演示文稿中做了),但是让我们再进一步补充一点.....
一个重要的附录:
(感谢 @BretKuhns 提出这个问题并在 cmets 中提供示例。)
这整个概念有一个令人讨厌的地方。说shared_ptr<const T> 表现得像值类型并不一定是正确的,除非我们知道对T 实例的所有活动指针/引用都是const。这是因为const 修饰符是单向街道——持有shared_ptr<const T> 可能会阻止我们 修改T 的实例,但不会阻止其他人 em> 通过指向非const 的指针/引用修改T。
知道了这一点,除非我知道指向它的所有活动指针都是 const,否则我会厌倦泛泛地声明 shared_ptr<const T> 与值类型一样好。但是,知道这样的事情需要对 shared_ptr<const T> 的所有用法的代码有全局了解——这对于值类型来说不会是问题。出于这个原因,这样说可能更有意义:A shared_ptr<const T> 可用于支持值语义。
顺便说一句,我实际上参加了 2013 年的 Going Native ——也许你可以在左前方看到我的后脑勺。