假设我有一个名为Vector
的std::vector
现在在向量上执行一些操作(插入或删除),我想检查向量是否为空,然后根据此执行某些操作。
哪种方法更好?
方法1
if (Vector.size() == 0){ /* operations */ }
方法二
if (Vector.empty()) { /* operations */ }
哪种方法更好,1
还是 2
?
v.size() == 0
表示“我正在比较大小”,但实际上是为了检查容器是否为空。在你理解它的含义之前,需要消化一个小算法(非常小,因为它只包括一次比较)。
另一方面,v.empty()
正好做了它所说的事情:它检查v
是否为空。
由于这个原因,我明显更喜欢第二种方法,因为它做了它所说的事情。这就是为什么empty()
被发明出来的原因。
但是也有一个算法上的原因更喜欢empty()
:如果将std::vector
更改为std::list
,v.size()
可能具有O(n)的时间复杂度。(在C++ 03中,对于std::vector
,它保证是O(1),但对于std::list
不是。根据James在Prasoon的回答中的评论,对于所有容器在C++1x中都将是O(1)。)
list
的权衡取舍(实际上是splice()速度与size()速度之间的权衡)。我现在似乎无法获取到这份白皮书,但是Michael Burr对其进行了总结。 - James McNellisempty()
的问题在于英语中的歧义性。不清楚“empty”是动词还是形容词! - sergiol第二种方法更好,因为无论容器类型如何,empty()
总是在常数时间内运行 [即 O(1)]。
size()
对于std::vector
也会在O(1)
的时间内运行,但对于std:list
则可能需要O(n)
的时间运行[实现方式有所不同]
在《Effective STL》[Item 4]一书中,Scott Meyers表示
你应该优先选择使用 empty 的方法,原因很简单:对于所有标准容器来说,empty 都是一个常数时间(constant-time)操作,但对于某些list实现,size却需要线性时间。
.....
无论发生什么情况,如果你调用 empty 而不是检查 size() == 0,都不会出错。因此,每当您需要知道一个容器是否有零个元素时,请调用 empty。
size()
几乎可以保证是 O(1),尤其是对于 vector
。在 C++0x 中,任何实现了 size()
的容器都必须保证其时间复杂度为 O(1)。 - James McNellissize()
应该具有常数时间复杂度(这意味着根本没有复杂度要求)。C++0x对此进行了改变。当我在第一条评论中说“对于任何实现它的容器”时,我是错误的;所有容器都必须实现size()
。 - James McNellisvector
?! - sergiolempty
方法特别适用于 std::list
,因为计算它们的大小可能会非常耗时。 - Benoitlist
的实现具有常数时间的size()
;在C++0x中,size()
将被要求对于所有容器,包括list
,具有常数时间复杂度。 - James McNellismy_list::size
为O(N)的情况。 - Potatoswattersplice
是O(n),但我非常确定它需要是O(1)。 - Oliver Charlesworthcapacity
和size
。向量的size
是实际元素的数量,而容量是动态数组的大小。size()
将简单地获取成员size
。
empty()
将返回比较结果size == 0
。O(1)
,但如果要检查向量是否为空,则建议使用empty()
。因为这就是该函数的作用。这将使您的代码更易于阅读。std :: vector
切换到std :: list
)。 - Oliver Charlesworth.empty()
的一个不好的地方是它并不清楚它是一种操作,将从容器中删除所有元素,还是告诉你容器是否为空。isEmpty()
更符合我的风格。但这就是标准库命名约定的本质。我必须遵循“入乡随俗”的规则;你应该优先考虑容器变化的更好不变式。因此,某人浏览代码库并用 x.empty()
替换所有 x.size() == 0
模式是有道理的——在这种情况下,我认为这是正确的答案。 - HostileFork says dont trust SE只是为了好玩:为什么不呢:
if(Vector.begin() == Vector.end())
?
使用 empty()。