使用引用而非指针

大约一个月前,我思路清晰,开始将 WebKit 代码转换为在传递已知存在的对象时使用引用而非指针。一开始我只是随便玩玩,但后来逐渐变得认真起来,其他人也开始贡献补丁。

Darin 建议我写这篇博客文章,以澄清关于为何/何时使用引用的任何困惑,所以我们直奔主题!使用例如 Frame& 而非 Frame* 有两个主要原因。

原因一

它表明我们正在引用一个现有的 Frame 对象,并且可以安全地调用其成员函数。

对比这个例子

// WebKit in 2012, so gaudy!
return m_page->mainFrame()->eventHandler()->mousePressed();

与此

// WebKit in 2013, so fab!
return m_page.mainFrame().eventHandler().mousePressed();

在旧版本中,m_pagemainFrame()eventHandler() 是否非空并不清楚。事实上,你需要对 WebCore 对象模型有相当好的理解,才能知道哪些指针可能为空,哪些不能。函数中充斥着这样的检查是很常见的:

if (!m_page)
    return false;
if (!m_page->mainFrame())
    return false;
if (!m_page->mainFrame()->eventHandler())
    return false;

这引出了原因二

它通过将不必要的空检查转换为编译错误来暴露它们。

C++ 不允许你对引用进行空检查,所以你别无选择,只能移除它们。这很棒,因为它意味着更小、更快的代码,无论是二进制文件还是源代码。CPU 不必花费时间检查对象是否真的存在,你也不必花费时间担心如果它不存在该怎么办。每个人都是赢家!

那么何时应该使用引用呢?

  • 如果你要返回一个指针,但你知道它永远不会为空,那就把它变成引用!
  • 如果你接受一个指针参数,但你不希望处理它为空的情况,那就把它变成引用!
  • 如果你的类有一个在构造后永不更改的指针成员,那就把它变成引用!
  • 但是,如果你的代码有 RefPtr<Frame>,请注意切换到 Frame& 将不再对 Frame 进行引用/解引用,这可能不是你想要的!

我的梦想是有一天,如果我看到一个 -> 或一个 *解引用,前面几行也会有一个空检查(或者一个解释为何可以安全解引用的注释)。这可能不完全现实,但让我们看看我们能走多远。