【问题标题】:Why use references rather than pointers?为什么使用引用而不是指针?
【发布时间】:2013-02-09 08:25:09
【问题描述】:

当没有对引用进行编译时类型检查时,为什么要使用引用而不是指针?

假设您正在创建一个Person 类型的对象,该对象需要保存指向其House 的引用/指针(非常随机) - 因此人员对象会将房屋引用/指针保存为数据成员。想象一下这是通过引用完成的:

class Person{
   public:
      Person(House& myHouse) : house(myHouse) { }
   private:
      House& house;
};

我看到的问题是,如果您忘记在数据成员声明中包含 & ,那么您认为是引用的东西就会变成副本。传递并保存指针肯定会更安全,以便在编译时标记此错误?

我并不是要使用其中一个或另一个 - 我在问为什么要使用引用而不是指针来保存数据成员?

【问题讨论】:

  • 该代码不合法​​。成员引用未在构造初始化器列表中初始化。
  • 您附加的 sn-p 不是有效的 C++ 代码。 必须使用现有对象初始化引用。
  • 如何传递指针比现在更安全?事实上,如果您的成员是指针,编译器不会捕获您在您编辑之前展示的问题(未能在初始化器列表中初始化您的引用) .
  • “我看到的问题是,如果你忘记在数据成员声明中包含 & ,那么你认为是引用的东西就会变成副本” - 如果你“忘记“那么您可能是初学者,这对您来说将是一次学习经历。我的意思是,它可能发生在一个更有经验的开发者身上,但我不记得上次我“忘记”引用参考是什么时候了。
  • @Frammo 然后你今天学到了一些东西,并且感谢 SO。 ;)

标签: c++ pointers reference pass-by-reference


【解决方案1】:

我并不是要使用其中一个或另一个 - 我在问为什么要使用引用而不是指针来保存数据成员?

指针和引用都用作数据成员。参考T& 与不可变指针T* const 一样灵活。此外,引用可能不为空。因此,如果这些属性以最佳方式描述了您的需求,请使用参考。

IOW,如果每个Person 都必须有一个House 并且PersonPerson 的生命周期内不能切换到其他House,则使用引用。显然这两个前提都让人觉得很荒谬,所以指针实际上可能更好。

指针并不总是更好。当事物保持不变时,支持不变性 (int* const) 到可变性 (int*)。当事情确定时,倾向于确定性(完全是一个)而不是不确定性(一个或没有)。

在 OOP 中,组件对象中的组合关系通常作为对组合对象的引用来完成。一个组件没有复合就不能存在,也不能成为其他复合的组件,所以最好参考。

【讨论】:

  • "如果每个Person 都必须有一个House 并且PersonPerson 的生命周期内不能切换到其他House 然后使用引用" - 没有。这意味着House类型的对象必须在Person类型的对象被构​​造之前存在,并且无论发生什么,Person类型的对象所指的House类型的原始对象都应该被改变。而不是重新分配给House 类型的另一个对象。换句话说:指针与引用不是受数据模型设计影响的决定
  • @LihO 愿意解释一下这个案子……除非房子在他出生之前就已经存在,否则他的房子怎么可能在他的一生中不会改变?指针与引用与对象之间的关系类型有关。
  • “一个人怎么可能拥有一生不变的房子”——这正是我的观点。引用不会引用不同的对象,但这并不意味着它所引用的对象不能改变。
  • @Liho 我的意思是“改变”,意思是“与其他房子切换”,而不是“用不同颜色画房子”。我的回答包含措辞。
  • 想象一下Person的这种方法:void moveTo(House& newHouse){ house = newHouse; }
【解决方案2】:

如果您忘记在数据成员声明中包含 & ,那么您认为是引用的东西变成了副本...传递并保存指针会更安全,这样这个错误就会在编译时被标记出来时间?

不能在声明成员时忘记输入& 符号。无论你写House& house 还是House house 都是你的决定,编译器应该尊重。当您更改对对象的引用声明时,您是有意这样做的。这不是你的编译器应该警告你的事情。

编译器无法知道您是打算通过值传递还是通过引用传递。当您将按指针传递更改为按值传递时,编译器报告错误只是因为您将副本(具有自动存储持续时间的对象)视为指针(在语法上不正确),而不是因为它能够识别您可能意味着通过指针传递。

为什么在指针上使用引用来保存数据成员?

主要原因是确保引用始终使用现有对象进行初始化,这也意味着没有NULL-check 错误处理和在编译类型而不是运行时捕获可能的错误。其他争论可能是更简洁的代码(可读性),在我看来,使用引用也会导致人们依赖具有自动存储持续时间的对象并学会遵循RAII 习惯用法,而不是进入丑陋的内存管理和内存泄漏的地牢。

但我相信您会发现许多现有的问题来解决这个问题,例如Pointer vs. Reference

【讨论】:

    猜你喜欢
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-17
    • 1970-01-01
    • 2011-09-17
    相关资源
    最近更新 更多