Advancing Through std::vector

M

Mike Copeland

I have a std::vector of some size (I know I can get the size with the
..size() function, but that doesn't help my question here). I have logic
which processes "chunks" of this data, 20 at a time. Let's say that I
have 32 objects in the container, and my first "page" of data is 1-20.
The next "chunk" can't be 20, and I obviously have to protect against
trying to access object(s) that don't exist. Normal incrementing of the
iterator (e.g. advance) or direct indexing don't seem to offer ways to
avoid accessing beyond the data set. That is, I can't find any STL
functions that give me ways to avoid problems here.
Yes, I could do some convoluted math that works with .size(), but if
I'm using an iterator and advance, the work seems messy and ugly. 8<{{
So I asking here if there is some way to use/convert the iterator
position and apply it to see if it's "gone beyond" the container's data
set. Perhaps there's a function that returns an indicator, or maybe
someone who's dealt with this problems has a good solution. TIA
 
R

red floyd

I have a std::vector of some size (I know I can get the size with the
.size() function, but that doesn't help my question here). I have logic
which processes "chunks" of this data, 20 at a time. Let's say that I
have 32 objects in the container, and my first "page" of data is 1-20.
The next "chunk" can't be 20, and I obviously have to protect against
trying to access object(s) that don't exist. Normal incrementing of the
iterator (e.g. advance) or direct indexing don't seem to offer ways to
avoid accessing beyond the data set. That is, I can't find any STL
functions that give me ways to avoid problems here.
Yes, I could do some convoluted math that works with .size(), but if
I'm using an iterator and advance, the work seems messy and ugly. 8<{{
So I asking here if there is some way to use/convert the iterator
position and apply it to see if it's "gone beyond" the container's data
set. Perhaps there's a function that returns an indicator, or maybe
someone who's dealt with this problems has a good solution. TIA

auto dist = std::distance(iter, vec.end());
if (dist >= 20)
dist = 20;
std::advance(iter, dist);
 
R

red floyd

I have a std::vector of some size (I know I can get the size with the
.size() function, but that doesn't help my question here). I have logic
which processes "chunks" of this data, 20 at a time. Let's say that I
have 32 objects in the container, and my first "page" of data is 1-20.
The next "chunk" can't be 20, and I obviously have to protect against
trying to access object(s) that don't exist. Normal incrementing of the
iterator (e.g. advance) or direct indexing don't seem to offer ways to
avoid accessing beyond the data set. That is, I can't find any STL
functions that give me ways to avoid problems here.
Yes, I could do some convoluted math that works with .size(), but if
I'm using an iterator and advance, the work seems messy and ugly. 8<{{
So I asking here if there is some way to use/convert the iterator
position and apply it to see if it's "gone beyond" the container's data
set. Perhaps there's a function that returns an indicator, or maybe
someone who's dealt with this problems has a good solution. TIA

Why doesn't size() help you?

cur_index = &*it - &vec.begin();
int items_left = vec.size() - 20;
chunk_size = items_left > 20 ? 20 : items_left;
 
V

Victor Bazarov

auto dist = std::distance(iter, vec.end());
if (dist >= 20)
dist = 20;
std::advance(iter, dist);

In addition to what red said, the vector iterator is of "random access"
variety, so they are comparable using < and >. Your chunk processor
need to still somehow know the end of the container, though. Iterators
do not carry that information I'm afraid.

V
 
J

Jorgen Grahn

I have a std::vector of some size (I know I can get the size with the
.size() function, but that doesn't help my question here). I have logic
which processes "chunks" of this data, 20 at a time. Let's say that I
have 32 objects in the container, and my first "page" of data is 1-20.
The next "chunk" can't be 20, and I obviously have to protect against
trying to access object(s) that don't exist. Normal incrementing of the
iterator (e.g. advance) or direct indexing don't seem to offer ways to
avoid accessing beyond the data set. That is, I can't find any STL
functions that give me ways to avoid problems here.
Yes, I could do some convoluted math that works with .size(), but if
I'm using an iterator and advance, the work seems messy and ugly. 8<{{
So I asking here if there is some way to use/convert the iterator
position and apply it to see if it's "gone beyond" the container's data
set. Perhaps there's a function that returns an indicator, or maybe
someone who's dealt with this problems has a good solution. TIA

No worries. I'd just do something like this:

vector<Foo> v;
vector<Foo>::iterator a = v.begin();

while(a!=v.end()) {
vector<Foo>::iterator b = v.size()>20 ? a+20 : v.end();
process(a, b);
a = b;
}

/Jorgen
 
M

Mike Copeland

So I asking here if there is some way to use/convert the iterator
Why doesn't size() help you?

cur_index = &*it - &vec.begin();
int items_left = vec.size() - 20;
chunk_size = items_left > 20 ? 20 : items_left;
Well, I didn't know how to use the code this way. That's clever, and
I appreciate the lesson. 8<}}
 
F

Fred Zwarts \(KVI\)

-----Original Message-----
From: red floyd Sent: Wednesday, September 11, 2013 10:01 PM Newsgroups:
comp.lang.c++ Subject: Re: Advancing Through std::vector


Why doesn't size() help you?

cur_index = &*it - &vec.begin();
int items_left = vec.size() - 20;

I think you meant
int items_left = vec.size() - cur_index;
 
F

Fred Zwarts \(KVI\)

"Jorgen Grahn" wrote in message
No worries. I'd just do something like this:

vector<Foo> v;
vector<Foo>::iterator a = v.begin();

while(a!=v.end()) {
vector<Foo>::iterator b = v.size()>20 ? a+20 : v.end();

Shouldn't that be something like
 
J

Jorgen Grahn

"Jorgen Grahn" wrote in message


Shouldn't that be something like

Uh, yes, of course. You cannot base the size of the range on the size
of v -- it must be based on the size of the remaining part.

/Jorgen
 
K

K. Frank

Hello Group (and Victor)!

...
In addition to what red said, the vector iterator is of "random access"
variety, so they are comparable using < and >. Your chunk processor
need to still somehow know the end of the container, though. Iterators
do not carry that information I'm afraid.

Just to confirm my understanding here ...

As Victor said, vectors are random-access containers,
so one can do something like this:

vector_it += 17;

But, officially, you can't run off the end of the
vector:

// legal -- points to one past end
vector_it = vec.begin() + vec.size();
if (vector_it >= vec.end()) { // will be true }

// undefined behavior, even if iterator is
// not dereferenced
if (vec.begin() + vec.size() + 1 > vec.end()) {}

Presumably, if you don't dereference the iterator,
my above example would work "correctly" on almost
all implementations almost all of the time, but, as
I understand it, creating an iterator that points
_past_ one past the last element is undefined
behavior, even if the iterator isn't dereferened.

Do I have this right?


Thanks.


K. Frank
 
J

Jorgen Grahn

Hello Group (and Victor)!



Just to confirm my understanding here ...

As Victor said, vectors are random-access containers,
so one can do something like this:

vector_it += 17;

But, officially, you can't run off the end of the
vector:

// legal -- points to one past end
vector_it = vec.begin() + vec.size();
if (vector_it >= vec.end()) { // will be true }

// undefined behavior, even if iterator is
// not dereferenced
if (vec.begin() + vec.size() + 1 > vec.end()) {}

Presumably, if you don't dereference the iterator,
my above example would work "correctly" on almost
all implementations almost all of the time,

Seems to me you're trying too hard to rationalize doing this. Just
don't do it. There's no need to, and it will confuse your readers.
Also I'm not at all sure it will work as you expect as often as you
think. Running in debug mode, for example ...

It's so much easier to write correct code, compared to writing buggy
code and then worrying about situations which may reveal the bug.
as
I understand it, creating an iterator that points
_past_ one past the last element is undefined
behavior, even if the iterator isn't dereferened.

Do I have this right?

Yes.

/Jorgen
 
R

red floyd

Well, I didn't know how to use the code this way. That's clever, and
I appreciate the lesson. 8<}}

This trick ONLY works with vector, because vector is guaranteed to
be contiguous.
 
S

SG

Seems to me you're trying too hard to rationalize doing this. Just
don't do it. There's no need to, and it will confuse your readers.
Also I'm not at all sure it will work as you expect as often as you
think. Running in debug mode, for example ...

Exactly! I ran into this when I wrote a simple vector wrapper for a
2D raster data structure (row major storage) and tried to iterate over
a column à la

auto iter = ...;
for (int row=0; row<nrows; ++row) {
...
iter += ncols; // oops!
}

Everything seemed to work fine (in release mode) except that
libstdc++'s debug mode detected the iterator-beyond-valid-range
condition.
It's so much easier to write correct code, compared to writing buggy
code and then worrying about situations which may reveal the bug.

I totally agree.

Cheers!
SG
 
J

James Kanze

Why doesn't size() help you?
cur_index = &*it - &vec.begin();

Why not just "it - vec.begin()".
int items_left = vec.size() - 20;

or if this is what you're after:

int items_left = vec.end() - it;
chunk_size = items_left > 20 ? 20 : items_left;

or the simplest:

chunk_size = std::min( vec.end() - it, static_cast<ptrdiff_t>(20) );

(The static_cast is only necessary because we don't know the
real type of "vec.end() - it". It's ptrdiff_t, but that may be
int, long or long long, depending on the implementation.)
 
J

James Kanze

"Jorgen Grahn" wrote in message
Shouldn't that be something like
vector<Foo>::iterator b = v.end()-a >20 ? a+20 : v.end();

Or even:
ptrdiff_t const chuckSize = 20;
vector<Foo>::iterator b = a + std::min( chuckSize, v.end() - a );

If you add "v.end() - a" to "a", you're guaranteed to be
a v.end();
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top