WebKit 与 C++11
我很高兴地宣布,自 r155146 起,我们现在要求我们的各种端口使用支持某些 C++11 特性的编译器进行构建。这意味着我们不再需要使用 COMPILER_SUPPORTS()
宏来有条件地使用这些特性。这些特性包括:
- 类型推断
- 静态断言
- 移动语义
我们选择了这三个特性,因为它们在我们使用的最新编译器版本中得到了很好的支持:clang、MSVC 和 GCC。
这对编写代码的人意味着什么?以下是三个示例代码,展示了这三个特性的用武之地:
类型推断
使用 auto
关键字的类型推断将根据变量的初始化器自动推断其类型。这对迭代器尤其有用。此循环
HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator end = m_counters.end();
for (HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator iter = m_counters.begin(); iter != end; ++iter) {
...
}
变为
for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) {
...
}
不幸的是,新的基于范围的 for 循环语法并非所有编译器都支持,但这无疑是朝着正确方向迈出的一步。
静态断言
新的 static_assert
是一种声明编译时断言的方法。如果断言为 false
,编译器将产生错误。WTF 已经有一个提供此功能的 COMPILE_ASSERT
宏,但 static_assert
会生成更好的错误消息。
COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size);
给出错误
/Source/WTF/wtf/text/AtomicString.cpp:43:1: error: 'dummyatomic_string_and_string_must_be_same_size' declared as an array with a negative size
COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Source/WTF/wtf/text/AtomicString.cpp:23:
In file included from /Source/WTF/config.h:62:
In file included from /Source/WTF/wtf/FastMalloc.h:25:
In file included from /Source/WTF/wtf/PossiblyNull.h:29:
/Source/WTF/wtf/Assertions.h:324:60: note: expanded from macro 'COMPILE_ASSERT'
#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]
而
static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must have the same size");
给出
/Source/WTF/wtf/text/AtomicString.cpp:43:1: error: static_assert failed "AtomicString and String must have the same size"
static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must have the same size");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
移动语义
移动语义可以在按值传递对象时,通过移动数据而不是复制数据来提高性能。对于 WebKit 来说,这意味着我们可以在返回 Vector
的函数中停止使用 out 参数。例如:
void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
elements()->namedItems(name, namedItems);
HTMLElement* elementFromPast = elementFromPastNamesMap(name);
if (namedItems.size() == 1 && namedItems.first() != elementFromPast)
addToPastNamesMap(toHTMLElement(namedItems.first().get())->asFormNamedItem(), name);
else if (elementFromPast && namedItems.isEmpty())
namedItems.append(elementFromPast);
}
变为
Vector<RefPtr<Node>> HTMLFormElement::namedElements(const AtomicString& name)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
Vector<RefPtr<Node>> namedItems = elements()->namedItems(name);
HTMLElement* elementFromPast = elementFromPastNamesMap(name);
if (namedItems.size() == 1 && namedItems.first() != elementFromPast)
addToPastNamesMap(toHTMLElement(namedItems.first().get())->asFormNamedItem(), name);
else if (elementFromPast && namedItems.isEmpty())
namedItems.append(elementFromPast);
return namedItems;
}
移动语义是一个有趣的话题,我希望在另一篇博客文章中进一步探讨,所以这里只做简要提及。
还有一件事
敏锐的读者可能已经注意到上一个例子中我们现在可以使用的另一个 C++11 特性。在 C++11 中,关闭模板参数列表时,右尖括号之间不再需要空格!这意味着
OwnPtr<Vector<RefPtr<Node> > > m_childNodes;
变为
OwnPtr<Vector<RefPtr<Node>>> m_childNodes;
我个人对使用这些特性感到非常兴奋,我认为它们将在整个代码库中发挥作用。未来我们将开始要求支持更多 C++11 特性,但这是一个好的开始。