Do I really have to use an array?

A

Alf P. Steinbach

* mike3:
I was using int instead of std::size_t becuase loops like
this, which are used in several routines, do not work:

---
std::size_t myLength(myVector.size());

for(std::size_t i(myLength-1);i>=0;i--)
{
... do something ...
}
---

"i" decreases down beyond zero. But with an int, ie.

---
int myLength(myVector.size());

for(int i(myLength-1);i>=0;i--)
{
... do something ...
}
---

it works fine.

Does that make any sense? It seems you've just got to have
a conversion somewhere.

If you want the range myLenght-1 downto 0, inclusive, consider just

for( size_t i = myLength-1; i != size_t(-1); --i )


Cheers, & hth.,

- Alf
 
A

Andrew Koenig

If you want the range myLenght-1 downto 0, inclusive, consider just
for( size_t i = myLength-1; i != size_t(-1); --i )
Cheers, & hth.,

I have to say that this example is too clever for my taste. I'd rather
write:

for (size_t i = myLength; i != 0; ) {
--i;

// whatever

}

One reason for my preference is that this technique works for bidirectional
iterators too:

for (list<T>::iterator it = myList.end(); it != myList.begin(); ) {
--it;

// whatever

}

whereas the "myLength-1" technique doesn't.
 
A

Alf P. Steinbach

* Andrew Koenig:
I have to say that this example is too clever for my taste. I'd rather
write:

for (size_t i = myLength; i != 0; ) {
--i;

// whatever

}

I have to say that that example is too clever for /my/ taste... ;-)

With a for-loop, except "for(;;)", one expects the expression that in
some sense "counts" (or less informally speaking, controls the loop
variant), to be in the loop head, after that last semicolon.

Also, one expects the initializer to be the first value for the loop
control variable.


One reason for my preference is that this technique works for bidirectional
iterators too:

for (list<T>::iterator it = myList.end(); it != myList.begin(); ) {
--it;

// whatever

}

whereas the "myLength-1" technique doesn't.

Hm. I don't think it's necessarily a good idea to press different kinds
of code into the same form, or using the possibility of doing so as a
positive guideline. And I think the above would be better expressed
using reverse iterators, placing the update in the for loop head, like


typedef list<T>::reverse_iterator RIterator;

for( RIterator it = myList.rbegin(); it != myList.rend(); ++it )
{
// Whatever
}


And just an idea, essentially the same can be accomplished for integer
indices,

#include <cstddef>
#include <iostream>

struct RIndex
{
size_t current;
size_t end;

RIndex( size_t firstValue, size_t lastValue = 0 )
: current( firstValue ), end( lastValue - 1 )
{}

operator size_t() const { return current; }
bool atEnd() const { return (current == end); }
void advance() { --current; }
};

int main()
{
using namespace std;

static int const myList[] = {1, 2, 3};
static size_t const myLength =
sizeof(myList)/sizeof(*myList);

for( RIndex i = myLength-1; !i.atEnd(); i.advance() )
{
cout << myList << endl;
}
}

where not using the iterator idiom (operator*, operator++) is
intentional, since it's not really an iterator.

Cheers,

- Alf
 
R

Richard Herring

In message
Nice obfuscation.

That's another word for "idiom", isn't it? Guaranteed termination, loop
invariant exists throughout the block, ... what more do you want?

(And it doesn't use break ;-)
 
J

James Kanze

* Andrew Koenig:

Because it depends on the modulo arithmetic of unsigned types?
(I'll admit that I'm not too fond of it for this reason either.
It's not a context where I'd expect modulo arithmetic.)
I have to say that that example is too clever for /my/ taste... ;-)
With a for-loop, except "for(;;)", one expects the expression
that in some sense "counts" (or less informally speaking,
controls the loop variant), to be in the loop head, after that
last semicolon.
Also, one expects the initializer to be the first value for
the loop control variable.

So write it:

size_t i = myLength ;
while ( i != 0 ) {
-- i ;
// ...
}

There seems to be a great deal of variance with regards to what
is considered acceptable in a for. Like you, I more or less
expect to find three parts (although it doesn't bother me too
much if the first is missing), and more importantly, that if the
control variable is modified in some way, that modification
takes place in the third part, and not elsewhere. Which means
that in this case, I would use a while, and not a for.
Hm. I don't think it's necessarily a good idea to press
different kinds of code into the same form, or using the
possibility of doing so as a positive guideline. And I think
the above would be better expressed using reverse iterators,
placing the update in the for loop head, like
typedef list<T>::reverse_iterator RIterator;
for( RIterator it = myList.rbegin(); it != myList.rend(); ++it )
{
// Whatever
}

This is definitly the way the STL was designed to be used.
Whether it is a good idea or not is another question. It sort
of hides the fact that you are going backwards, which may be the
sort of necessary information you don't want to hide. I also
find it rather confusing that when you extract the base
iterator, it is off by one.
 
R

Richard Herring

In message
Readability.
If it's an idiom, you don't need to read it. Whether it's an idiom is
ultimately a question of style guides and/or familiarity. If you want to
say that all reverse-indexing (as opposed to hiding the reversal inside
reverse iterators) is inherently unidiomatic, I wouldn't argue.
 
R

Ralph D. Ungermann

James said:
Nice obfuscation.

The postfix `trick' is uncommon, but not unknown. After a first
irritation, one ought to get it -- and remember, if repeated.

Though the decrement is more correctly placed at the beginning of the
loop, this does neither enhance readability nor safety (IMHO).

I've seen too much code, where each loop has been handcrafted: mixing
int and size_t, cast both ways, decrementing i on-the-fly at the first
occurrance in the loop body, and worse. You'll agree, that this causes
much more obfuscation.

So I use my way, whenever I have to: using uncommon syntax for uncommon
loops.

But as you mention it, I'm willing to change my style to:

for ( std::size_t i = myLength; i--; /*backward*/ )


-- ralph
 
R

Richard Herring

Ralph D. Ungermann said:
The postfix `trick' is uncommon, but not unknown. After a first
irritation, one ought to get it -- and remember, if repeated.

Though the decrement is more correctly placed at the beginning of the
loop, this does neither enhance readability nor safety (IMHO).

I've seen too much code, where each loop has been handcrafted: mixing
int and size_t, cast both ways, decrementing i on-the-fly at the first
occurrance in the loop body, and worse. You'll agree, that this causes
much more obfuscation.

So I use my way, whenever I have to: using uncommon syntax for uncommon
loops.

But as you mention it, I'm willing to change my style to:

for ( std::size_t i = myLength; i--; /*backward*/ )
I was happy with this until yesterday, when a colleague pointed out that
the equivalent for iterators:

for (iterator i=container.end(); i-- != container.begin(); )
{
//...
}

doesn't work if the container is empty, whereas this is fine:

for (iterator i=container.end(); i != container.begin(); )
{
--i;
//...
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top