在做LeetCode 208. 实现 Trie (前缀树) 的时候,第一次提交速度上仅仅比C++ 23.7%的人快,感觉有点问题,会过初步分析了下,发现前缀树节点 TrieNode 的初始化实现有问题,严格来说,第一次的实现不是初始化,而是赋值,具体代码如下
struct TrieNode {
TrieNode():count(0) {
for(auto& p : next) {
p = nullptr;
}
}
int count;
TrieNode* next[26];
};
请注意构造中的 for循环,指针数组 next 采用了26次循环分别给每个指针赋值 nullptr(注意,是赋值,不是初始化,在赋值前,每个指针值是不确定的),显然是非常愚蠢的做法,因此提交后速度上很明显较慢,上图。
由于现代C++ (C++11及以后)已经支持类对象成员的类内初始化(其实不说现代C++,也不应该如上那种愚蠢的写法,因为C++11以前也支持直接初始化),优化如下
struct TrieNode {
TrieNode(){}
int count{0}; // 直接初始化,初始化为0,如果采用值初始化也就是不写0,则同样初始化为0
TrieNode* next[26]{}; // 值初始化,初始化为nullptr
};
优化后效果还算比较明显,在C++中直接快于57%的人。
总结
1)C++内置类型成员在默认初始化的情况下,值不确定,采用值初始化则有确定的值,数值类型为0,指针类型为nullptr;
2)如果不是内置类型,比如自定义的类,则采用默认构造函数,当然,如果类的成员中包括内置类型,没有直接初始化的情况下值同样不确定,比如上述中TrieNode的成员count。
3)现代C++支持类内初始化,类成员类内初始化必须使用 = 的初始化形式(即拷贝初始化) 或者 花括号{}括起来的直接初始化形式。