Effective STL 第4条:调用empty()而不是检查size()是否为0
调用empty而不是检查size是否为0
- 为什么选择`empty()`?
- 1. **`empty()`是常数时间操作**
- 2. **`size()`的效率问题**
- 为什么`list`的`size()`会这么慢?
- 代码示例:`empty()` vs `size()`
- 使用`empty()`
- 使用`size()`
- 实现细节:`empty()`和`size()`的内部实现
- 1. **`vector`的实现**
- 2. **`list`的实现**
- 结论
在C++编程中,判断容器是否为空是一个常见的操作。Effective STL的第4条建议我们使用empty()
方法,而不是通过检查size() == 0
来判断容器是否为空。这一建议的核心原因是效率问题,尤其是在处理某些容器(如list
)时,empty()
的效率显著高于size()
。
为什么选择empty()
?
1. empty()
是常数时间操作
对于所有标准容器(如vector
、list
、deque
等),empty()
是一个常数时间操作。它直接返回一个布尔值,表示容器是否为空。例如:
if (container.empty()) {// 容器为空
}
无论容器的大小如何,empty()
的执行时间是恒定的。
2. size()
的效率问题
对于某些容器(如list
),size()
可能是一个线性时间操作。这是因为list
的实现基于双向链表,而链表没有维护一个直接的大小计数器。每次调用size()
时,容器需要遍历整个链表来计算元素的数量,这会导致性能下降。
例如:
if (container.size() == 0) {// 容器为空
}
对于list
来说,size()
的执行时间与容器的大小成正比,这在处理大数据量时会显著影响性能。
为什么list
的size()
会这么慢?
list
的size()
操作需要遍历整个链表来计数元素,这是因为list
的设计目标是支持高效的插入和删除操作,而不是高效的大小查询。为了实现高效的插入和删除,list
没有维护一个直接的大小计数器。因此,每次调用size()
时,容器需要遍历所有节点来计算大小。
此外,list
的某些成员函数(如splice
)会转移大量节点,而维护一个大小计数器会增加这些操作的复杂性和执行时间。因此,list
的设计者选择牺牲size()
的效率,以换取其他操作的高效性。
代码示例:empty()
vs size()
使用empty()
#include <list>
#include <iostream>int main() {std::list<int> my_list;if (my_list.empty()) {std::cout << "列表为空。" << std::endl;} else {std::cout << "列表不为空。" << std::endl;}return 0;
}
使用size()
#include <list>
#include <iostream>int main() {std::list<int> my_list;if (my_list.size() == 0) {std::cout << "列表为空。" << std::endl;} else {std::cout << "列表不为空。" << std::endl;}return 0;
}
对于list
来说,empty()
的执行时间远小于size()
,尤其是在处理大数据量时。
实现细节:empty()
和size()
的内部实现
1. vector
的实现
// vector的empty()实现
bool empty() const noexcept {return begin() == end();
}// vector的size()实现
size_type size() const noexcept {return end() - begin();
}
vector
的empty()
和size()
都是常数时间操作,因为它们直接依赖于begin()
和end()
指针。
2. list
的实现
// list的empty()实现
bool empty() const noexcept {return begin() == end();
}// list的size()实现
size_type size() const noexcept {return _M_node_count();
}
list
的empty()
是一个常数时间操作,而size()
需要遍历整个链表来计算节点数量,这导致其执行时间为线性时间。
结论
在判断容器是否为空时,empty()
是一个更高效、更可靠的选择。它不仅适用于所有标准容器,而且在处理list
等特定容器时,能够显著提高性能。因此,Effective STL的第4条建议我们优先使用empty()
,而不是通过size() == 0
来判断容器是否为空。