在调试时,我看到了STL vector :: empty()实现:
bool empty() const
{return (size() == 0); }
我相信,每当我们探测向量的空虚时,总是建议使用空的大小()。但是看到这个实现,我想知道,这样做有什么好处?相反,在调用empty时会有一个函数调用开销,因为它在内部调用size()== 0。
我认为empty()在list的情况下可能有用,因为size()不保证列表中的常量时间。为了验证我的假设,我检查了列表实现,并且令人惊讶的是,在列表中也找到了相同的实现,
return (size() == 0);
我现在有点困惑。如果empty在内部使用size()那么我们为什么要选择empty over size()?
答案 0 :(得分:43)
因为如果你从std :: vector切换到std :: list或其他容器,它可能会有所不同。
例如std::list::size
的某些实现采用O(n)
而非O(1)
。
答案 1 :(得分:25)
每次使用size()
时,您都需要写出条件。使用empty()
很方便。这当然是,如果你不切换容器。正如其他人所指出的那样,在size()
中使用empty()
是否可以实现。但是,该标准确保:empty()
是所有人的固定时间操作
标准容器。
答案 2 :(得分:10)
好吧,正如你所说,这只是一个实现细节。 std::list
可以使用存储的大小(常量size()
但线性时间splice()
)或不使用(常量splice()
但线性时间{{}来实现1}})。选择使用size()
时,如果您不需要知道尺寸,就可以避免投注实施细节。
答案 3 :(得分:6)
遵循标准,应该首选empty(),因为无论容器类型如何,它都具有恒定的时间复杂度。
在C ++ 03标准中,第23.1章,表65:容器要求
Operation: empty()
Return_type: convertible to bool
Semantics: equivalent to size()==0
Complexity: constant
似乎在您的STL实现中,他们将语义作为忽略复杂性要求的实际实现,或者size()是实现中的常量时间(存储字段)。
如果size()不是常量时间,请与供应商联系,了解std :: list<> :: empty()是否符合标准容器要求。
答案 4 :(得分:5)
1,当你想知道某些东西是否为空时,使用一个名为empty()
的函数会使代码更具可读性,这意味着你不必担心实现细节。这也意味着您的代码可以更容易地适应其他类型的容器,具有其他特征。
第二,这只是一个STL实现。 我的GNU C ++看起来像这样:
bool
empty() const
{ return begin() == end(); }
这最终会导致指针比较,而使用size()会导致减法(在此实现中)。
第三,它不太可能产生额外函数调用的开销,因为empty()
- 函数可能是内联的(在两个实现中)。
答案 5 :(得分:4)
empty()具有所有容器类的O(1)实现。 size()只能为某些容器提供O(n)实现;这就是为什么empty()是首选的原因。
答案 6 :(得分:1)
除了上面给出的理由之外,它还可以说比foo.size()== 0和/或!foo.size()
更清晰答案 7 :(得分:0)
除了可读性点,这是非常有效的,你所经历的只是一个特定实现的工件,而不是唯一可能的实现。
也就是说,没有理由或要求在vector和list case中或者在任何其他容器中使用size()实现empty()。如果有更好的替代方案,应该使用它们,除非图书馆的作者不称职,或者更合理,懒惰。
对于列表和O(1) - size()的性质,或缺少它,你应该考虑到列表可以实现size()为O(1)或splice(),但不是两者(考虑原因是一个有趣的练习。)所以在你的情况下,你检查的库可能已经实现了size()为O(1)(在这种情况下splice()将是O(n))因此可以实现在大小()方面的empty()而不牺牲性能,否则,这将是一个非常糟糕的库。
答案 8 :(得分:0)
首选使用empty()而不是size(),因为每个容器可能以不同的方式实现empty()实现以获得常量时间操作。
示例:
vector实现为: bool empty()const {//测试序列是否为空 return(size()== 0); }
list实现为:
bool empty() const
{ // test if sequence is empty
return (_Mysize == 0);
}