views:

216

answers:

7

Suppose I have a std::vector say Vector

Now after performing some operations on the vector(either insertion or deletion) I want to check if the vector is empty and on the basis of that I want to perform some operations.

Which approach is better

Approach 1

if (Vector.size() == 0){ /* operations */ }

Approach 2

if (Vector.empty()) { /* operations */ }

Which is a better approach, 1 or 2?

+6  A: 

Approach (2) would be better because empty() always runs in a constant time [i.e O(1)] irrespective of the container type.

size() too runs in O(1)[for std::vector] although it might run in O(n) for std:list [thats implementation defined to be honest]

In Effective STL[Item 4] Scott Meyers says

You should prefer the construct using empty, and the reason is simple: empty is a constant-time operation for all standard containers, but for some list implementations, size takes linear time.

.....

No matter what happens, you can't go wrong if you call empty instead of checking to see if size() == 0. So call empty whenever you need to know whether a container has zero elements.

Prasoon Saurav
No, `size()` is all but guaranteed to be O(1), especially for `vector`. In C++0x, `size()` will be required to be O(1) for any container that implements it.
James McNellis
@James: for lists as well?
sbi
@sbi: Yep; all containers. Currently the container requirements just say that `size()` _should_ have constant time complexity (which means that there isn't a complexity requirement at all). C++0x changes that. I was wrong in my first comment when I said "for any container that implements it," though; all containers must implement `size()`.
James McNellis
@James: Ah, didn't know that. I'll have to change my answer for that. Do you know what's the rationale for that change? It's a space-for-speed tradeoff, after all.
sbi
+6  A: 

I would say approch no 2, as method empty() was intentionally designed to check if an vector is empty. You may also check the efficiance of both approaches, and then decide which one is better.

Katalonis
The `empty` method is particularly good for `std::list`s because computing their size can be very.......long.
Benoit
@Benoit: Some implementations of `list` have a constant time `size()`; in C++0x, `size()` will be required to have constant time complexity for all containers, including `list`.
James McNellis
@James: Which is a good reason to use a custom or third-party `list`, if you happen to use `splice` and want *that* to be constant-time instead. Then, it's back to having `my_list::size` being O(N).
Potatoswatter
@James: Are you sure? As Potatoswatter said, this would require `splice` to be O(n), but I'm pretty sure it's required to be O(1).
Oli Charlesworth
@Oli: Yes. Splicing a range of nodes from another list has linear time complexity (all other splices have constant time complexity). This complexity requirement is the same in both C++03 and C++0x.
James McNellis
@Oli: I meant the need for such a noncompliant list template doesn't go away just because the Standard doesn't provide it. @James: +1
Potatoswatter
+2  A: 

If you are new to the programming, use one that has more meaning to you. For example if ==0 is more meaningful to you than .empty(), use that.

Later, if you have performance problems (which I strongly doubt that you will have here) use one that satisfies your performance targets.

Daniel Mošmondor
I'd rather my fellow-workers, newbies or not, use the one that has more meaning to experienced programmers. We'll all be experienced at some time, after all.
sbi
@sbi: Not only that, but the one that is better for performance in the long-run (e.g. if you switch from a `std::vector` to an `std::list` in the future).
Oli Charlesworth
@sbi: you got your point there - however, code is hard to read, you have to make it easy for yourself here and now.
Daniel Mošmondor
@Daniel: We all agree on that. We just don't all agree on _what_ is easy to read. When I taught C++, my students sometimes used the most hilarious constructs because to them (with whatever background they brought with them) it seemed to be easier to read that way. Which is why I'm cautious about telling them to write it the way they find it easiest to read.
sbi
@sbi: some code, when read, feels right and you don't have to translate it in your mind. that is the code you should write for yourself.
Daniel Mošmondor
@Daniel: The key phrase in your reply is "write for yourself". I've always worked in a team, and worked with code that was maintained and extended for a decade or longer. When you write code for _that_, you write code for those looking at it the next decade and you should write code that's easiest to understand for _them_. Those "them" might be you, ten years from now, or it might be someone else. So it's best to stick to conventions that are acknowledged as universally as possible rather than to your current preferences.
sbi
+11  A: 

v.size() == 0 says "I'm comparing the size", but does so to check whether the container empty. There's a small algorithm to digest (very small, as it only consists of a comparison) before you know what it does.
OTOH, v.empty() does exactly what it says: it checks whether v is empty.
Due to this, I clearly prefer #2, as it does what it says. That's why empty() was invented, after all.

But there's also an algorithmic reason to prefer empty(): If someone later changes std::vector into a std::list, v.size() might have O(n). (In C++ 03 it's guaranteed to be O(1) for std::vector, but not for std::list. According to James' comment to Prasoon's answer it will be O(1) for all containers in C++1x.)

sbi
In reply to your question/comment below, Howard Hinnant wrote up a whitepaper discussing the tradeoffs for `list` (it's actually a splice()-speed vs. size()-speed tradeoff). I can't seem to get to the whitepaper right now, but [Michael Burr summarized it.](http://stackoverflow.com/questions/228908/is-listsize-really-on/228914#228914).
James McNellis
@James: Thanks!
sbi
what is C++1x? :-|
Donotalo
@Donotalo: it's the new C++ standard that is going to be approved soon. For some time it was referred as "C++0x" (where 0x meant "in some year in range [2000, 2010)), but, since they didn't manage to get it approved before 2010, it's now also known as "C++1x". Some people still call it C++0x because it was called in that way or because they say that that "x" is to be intended as a hexadecimal digit.
Matteo Italia
i knew about C++0x but C++1x is new to me. thanks.
Donotalo
@Donotalo: it's just that the original rationale for the name C++0x is no longer valid, so while most of us prefer to stick with the name C++0x to avoid confusion, a few people think the upcoming standard's nickname should be changed to C++1x even if it means no one knows what we're talking about. ;) To add some bonus confusion, C++0x, whatever we call it, is unlikely to be the only revision to the standard this decade. So if we start calling it C++1x, it might end up clashing with *another* C++1x, denoting the *next* standard revision.
jalf
As far as I'm concerned, the bottom line is this: C++0x is not an official name. It is a placeholder, a nickname used to identify the draft that is not yet standardized. As such it *doesn't need to be updated*. They could call it C++1643 and it'd work just as well. So I'm going to keep calling it C++0x until the day it is standardized and receives an official name.
jalf
@jalf: That x is a placeholder for a not yet fixed digit. If there should be another TR before 2020 (per ISO rules, a new version of the standard must not be released in less than ten years), the x in the standard we're now waiting for is long settled and there's a digit found for it. (Also, by your logic, C++0x should clash with C++03.)
sbi
@sbi: the `x` is a placeholder yes, but the name as a whole is also a placeholder, so it doesn't really matter what it *means*. And C++0x doesn't clash with C++03 because no one ever used the name C++0x to refer to C++03.;) Remember I'm talking about how the names are actually used in practice, and not what meaning was intended when they were coined. To my knowledge, the C++0x name has never been used to refer to anything other than what's most likely going to end up being C++11. C++1x is much less established, and *could* refer to "C++0x+1" as well as C++0x itself.
jalf
also to my knowledge ISO has no such rule. I'm not sure where that rumor comes from, but I've never seen it confirmed. And the existence of C++98 as well as C++03 seems to contradict it, as do official statements by committee members (including Stroustrup) saying they were hoping for something like a new standard every 5 years once C++0x is finalized. (I'd assume they would know about it if ISO prohibited such a release schedule)
jalf
+3  A: 

Typically a vector is internally implemented as a pointer to a dynamically allocated array,and data members holding the capacity and size of the vector. The size of the vector is the actual number of elements, while the capacity refers to the size of the dynamic array.

Given this implementation, the member function size() will simply be a getter to the member size.

The empty() will return the result of the comparison size == 0.

So both are equally efficient O(1) but its recommended to empty() if you want to check if vector is empty. Because that is what the function is there for. It'll make your code easier to read.

codaddict
A: 

Go for empty().

nakiya
I (dis)like your reasoning for your opinion.
sbi
There should not be that much fuss about empty over size for vector right? :D
nakiya
A: 

Just for fun: why not:

if(Vector.begin() == Vector.end())

?

Benoit