使用引用而非指针
大约一个月前,我思路清晰,开始将 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_page
、mainFrame()
和 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 进行引用/解引用,这可能不是你想要的!
我的梦想是有一天,如果我看到一个 ->
或一个 *解引用
,前面几行也会有一个空检查(或者一个解释为何可以安全解引用的注释)。这可能不完全现实,但让我们看看我们能走多远。