Sam said:
To adopt a saying from another context: a few CPU cycles here, a few CPU
cycles there, a few bytes here, and a few bytes there, pretty soon
you'll be talking a real pig of an app.
std::list uses more memory and more allocations than std::vector does.
Thus using it is counter-productive if you don't require the few
advantages it has. Your suggestion of using std::list is a bad one. It
will result in inefficient memory-hog programs.
You are referring to indexing a vector to access its elements. That only
matters when random access is a requirement. It is not always required,
and not in this sample case.
And then you try to argue how std::list is so much better because you
can insert in the middle in constant time, as if that had been a
requirement in this case.
Furthermore, once again, you're trying to cobble together an argument by
blurring the distinction between practical and theoretical factors.
Practically, in OP's original case, a std::list was the most practical
approach.
I find it hilarious how you keep repeating that, yet show zero proof.
In the original poster's case the most practical approach is the
*simplest* approach, and std::vector is way simpler to use than std::list.
You didn't even disagree that iterating through the elements is
simpler with std::vector than it is with std::list, yet you refuse to
acknowledge that std::vector is the most practical approach exactly
because it's simpler to use.
Unable to form a practical argument, you have to retreat to making a
theoretical one, such that using a vector is "easier".
Unable to form a practical argument, you have to retreat to making a
theoretical one, such as insertion in the middle being faster.
Which feature is more practical in this case: Ease of usage, or an
unused feature? The easier syntax with std::vector is, in fact,
something which would actually be used, unlike your ridiculous argument
that inserting in the middle is faster.
Well, if you adopt a theoretical argument, you'll just have to take into
account all theoretical aspects of a std::vector, instead of
cherry-picking just the ones you like.
Good thing that you don't have to do the same with std::list.
You're going to have to consider
all of std::vector's baggage, such as excessive memory usage, excessive
copying, and iterator invalidation in analogous situations where a
std::list would not invalidate any of the existing iterators.
You are going to have to consider all the std::list's baggage, such as
excessive memory usage, slow allocation of a high amount of elements and
slow random access.
Practical test: Allocate 100 integers with std::vector and std::list,
and measure which one consumes more memory and is slower.
Also consider that often just *traversing* the elements will often be
slower with std::list than with std::vector because of cache issues
(traversing a list often causes more frequent cache misses than
traversing a vector, especially if the list elements happen to be at
random locations in memory, something which does not happen with vectors
nor deques).
But of course, you're always quick to close your eyes, and shut your
ears, when reality comes calling.
You are the one who is refusing to run his own test using more than 10
elements. Talk about deliberately closing your eyes from reality.
But, in singing the praises of std::vector, its fan club always fails to
consider these things.
And you fail to consider the drawbacks of std::list.
This, of course, is the theoretical world, and this is a valid
theoretical point.
Allocating 100 elements is a purely theoretical thing to do in your
world, it seems. I suppose allocating 1000 elements is completely beyond
the realm of reality then (not to talk about allocating 1 million elements).
What usually happens, at this point, is that the
vector fan club decides that they don't want to talk theory, at this
point, and revert back to some practical argument based on OP's original
scenario. Each time they're backed into a corner, they jump into some
other one.
I find it hilarious how it seems like you are talking about yourself.
You are accusing others of your own flaws.
I already answered it: the iterator one is simpler and easier to write,
for me.
Oh, so you are a liar too, it seems. You don't really think that the
loop using std::list iterators is simpler than the loop using an
integral counter, but of course you can't retract from your argument
now, so if doing so requires lying, that's a small price to pay.
It is the most natural fit with many STL iterator-based classes
and algorithms. Furthermore, when using the C++0x syntax, iterating over
a vector or a list is the same:
And you don't consider having to rely on a future not-yet-published
standard to be resorting to theoretical arguments?
Theory (in this type of conversation) means something which is not
practical, or something which cannot be put into practice. Resorting to
a yet-to-be-published standard is highly theoretical, rather obviously,
because you can't yet use the feature in practice.
This gives one an option of coding for an opaque container, which may be
implemented as either a std::list or a std::vector, without changing the
iterating code.
Good thing you don't have to resort to "theoretical stuff", but you
can keep with practical things relevant to the original problem.
You talk about either performance or ease of usage, depending on which
one is easier to shoehorn into your argument.
Ease of usage is and has always been better for std::vector. I don't
have to choose that argument depending on the situation. That argument
is true regardless.
*In addition* to that, std::vector is more efficient when the amount
of elements grows even slightly larger. Your std::list loses in both
counts in that case.
You know perfectly well what I'm talking about. You're just posturing,
due to a lack of any better argument.
Your argument was that when measuring performance, end() should not be
called in the conditional because it evaluates something. I asked you
what is it that it evaluates. You answered with some weird "every
iteration of the loop" which doesn't make any sense.
My point was that end() is not a heavy function. It doesn't evaluate
anything at all. ("Evaluate" would imply that it performs some algorithm
or some calculations, which is not the case.) All it does is to return
an iterator in constant time, which probably takes a couple of clock
cycles. Its speed is largely irrelevant.
That's not an answer to my question.
"Why does it matter?" "Because it does matter." That's not an answer.
It's just a childish "Why? Because!"
A small domain is not a valid excuse for a
sloppy implementation, in my book.
You want to optimize calling end() outside the loop. Well, how about
we optimize the speed testing program and put the std::vector instance
outside all the loops, so that at each iteration the same instance gets
reused over and over? See what the speed measurements tell then.
Or would that be "cheating"? Well, my answer to that would be your own
words: "A small domain is not a valid excuse for a sloppy
implementation, in my book."
If we are talking about micro-optimization, then we should use
micro-optimization with *all* testcases, not just with your pet container.
You should try striving to produce
the best, most efficient code, notwithstanding the situation, every
time. It's a good habit to have, and brings benefits in the long run.
Which is why you should use std::vector rather than std::list, unless
the few advantages of std::list overweight its disadvantages compared to
std::vector. Also std::deque should be considered as an alternative (and
as I have shown, it *is* the best choice in this particular case,
beating your pet std::list hands down.)