Sign in to follow this  
AcidZombie24

stl vector like iterator 2

Recommended Posts

AcidZombie, there's a ridiculously long-running bug on the forums which causes certain bits and pieces of code to do this to posts. I suggest that you post the code on this paste site and then link it here. I then suggest that you send about five emails to webmaster@gamedev.net asking them to fix the damn bug already.

Share this post


Link to post
Share on other sites
ok thanks
-----------
so i want to make a stl vector like iterator. i came up with this code.

1) if i want to do *b(25); how would i implement this?
2) i am sure begin() is wrong, it seems like what i do below is poor practice. How does stl (vector) really handle that? and yes, i look at the source :x. This is the closes i got

http://rafb.net/p/hPfxS051.html
-----------

since the site had an update (not to long after my post >_<), lets see this long post works below

Share this post


Link to post
Share on other sites
I just looked at your code and honestly, I have no idea what you're trying to do.

An iterator is supposed to behave like a pointer to an element in a container (like std::vector). It can "point" to a certain element in the container, can be "dereferenced" to get that element, and can be "moved" to traverse the container (depending on the container type, you may only be able to advance it one element at a time, or skip over several elements at once). Therefore, it's implementation is tightly coupled with the implementation of the container it's meant to work with (even though it's interface can be very generic, and in fact, that's the point of having an iterator in the first place).

In your code, there is no container, so what is your iterator supposed to do?

Share this post


Link to post
Share on other sites
More descriptive names are needed! It's very hard to work out what your code is for.

But some general advice.

operator++() (no int argument) should return a reference to *this.
operator++(int) should return a full object (not a reference) and can universally(?) be implemented as:

iterator operator++(int)
{
iterator ret(*this);
++*this;
return ret;
}


Why do your comparison operators return ints? What's wrong with bool?

Look up std::iterator<> and std::iterator_traits<>. Use one or the other so that your class interacts well with the standard library and other algorithms designed to use the same conventions.

The standard defines 5 different kinds of iterator:

* output
* input
* forward
* bidirectional
* random access

Decide which one yours is and implement the necessary interface. The further down the list you go, the more work it is to implement the required functionality for the given category.

But it's also true (except for input/output) that the further down the list you go, the greater the number of available algorithms can be used in conjunction with your iterators.

However! You may not want to implement one of the richer interfaces so that you allow room for maneuver in the implementation.

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
iterator operator++(int)
{
iterator ret(*this);
++*this;
return ret;
}


Why do your comparison operators return ints? What's wrong with bool?


It an example, i wont be using int as input and i wont be returning int or bool.

Quote:
Original post by the_edd
The standard defines 5 different kinds of iterator:

* output
* input
* forward
* bidirectional
* random access


its either input or forward, i dont really know the difference between the two. It looks like mutablility is the difference so i'll say it is input. (now that i thinking about it, forward allows both in and output?)

Where can i learn more about Iterator standards or about Input Iterator? i look at the sgi stl site and it ... isnt a great resource.

when receiving the value via *classVar; i want an optional parameter. either to modify the return value (of *classVar) or to get extended information. I would be doing *classVar( /*something*/ ); but when i try creating that syntax, i get a illegal indirection or other errors. Maybe i am not allowed to do that?

I am about to do *classVar alone and classVar(/*something*/) but not at the same time. Is doing them both possible?

[Edited by - AcidZombie24 on February 19, 2008 10:27:29 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by AcidZombie24
Quote:
Original post by the_edd
iterator operator++(int)
{
iterator ret(*this);
++*this;
return ret;
}


Why do your comparison operators return ints? What's wrong with bool?


It an example, i wont be using int as input and i wont be returning int or bool.


Huh? I mean your operator!= returns an int. It should return a bool. I'm not sure what you mean by "won't be using int as input"?

Quote:

its either input or forward, i dont really know the difference between the two. It looks like mutablility is the difference so i'll say it is input. (now that i thinking about it, forward allows both in and output?)


Yes, mutability in the sense that you can't modify what an input iterator refers to. You can only pull stuff out of it. A forward iterator implements the union of input and output iterators (more or less), as you suggest.

Quote:

Where can i learn more about Iterator standards or about Input Iterator? i look at the sgi stl site and it ... isnt a great resource.


Nicolai Josuttis' The C++ Standard Library has some easily digestible information. I haven't had the need to search for this info online, so I'm afraid I can't suggest anything. You could try dinkumware, maybe?

Quote:

when receiving the value via *classVar; i want an optional parameter. either to modify the return value (of *classVar) or to get extended information. I would be doing *classVar( /*something*/ ); but when i try creating that syntax, i get a illegal indirection or other errors. Maybe i am not allowed to do that?


Yeah all overloaded operators, except operator(), allow only a small range of signatures. You've wandered outside that range, here.

If you want whatever operator* gives you to have more information, then return a class with that information in it.

As phantom suggested, the boost iterator adaptors and framework is quite useful (once you stare at it long enough :)

Share this post


Link to post
Share on other sites
Quote:
Original post by AcidZombie24

It an example, i wont be using int as input and i wont be returning int or bool.


you have to use int as the argument to a postfix increment, it is the only way to write it.

Share this post


Link to post
Share on other sites
Iterators iterate over a container. Where's your container?

First, let's remove the unused stuff ('struct blah', and the virtual definitions - iterators are not supposed to be run-time polymorphic! The algorithms that use them are templated, instead.):


// There is no longer anything in the base class, and no real reason to have it.
// Also, everything is already public, so let's just use structs.
template <class T>
struct top {
// Being templated on 'class T' is implicit for the nested class.
// top<int>::s2 is a separate class from top<float>::s2.
struct s1 {
// "c" gets written to, but never *looked at*, so it's useless.
int i;
s1() {
i = 0;
}
// We don't use this parameter, so it doesn't need a name.
void operator++(int) {
i++;
// There is no reason to 'return' explicitly at the end of a void function.
}
void operator++() {
i++;
}
int operator!=(int a) {
return i != a;
}
T operator* () {
return i; // unless maybe you meant to return c here?
}
};
s1 begin() {
// Since the code reduced to "s1 a; return a;", we can simplify even further:
return s1();
}
int end() {
return 4;
}
};

#include <stdio.h>
void main() {
top<int> a;
top<int>::s1 b;
for (b = a.begin(); b != a.end(); b++) {
printf("%d\n", *b);
}
}



Next, we fix bugs:

- It makes more sense to implement operator== (you can then do a != comparison automatically; the other way around doesn't work. The standard library provides global, templated free function versions of operator!= etc. - you are expected to provide ==, and < if appropriate).
- Operator++ must return an instance of the class (either by value or by reference), in both cases.
- I assume you did want that 'c' after all. I'll use a constructor parameter to set it. But there's no need to increment 'c' all the time - we can use some logic in the operator* instead. (This also simplifies creating our end iterator and comparing it, since it will have the same 'c' value). Also, I'll give it a better name.
- end() must return an iterator, and our comparison must compare to an iterator. It should return a bool, too.
- main() must return int, not void.


template <class T>
struct top {
struct s1 {
int i, base;
s1(int base) : base(base) {
i = 0;
}
s1 operator++(int) {
s1 result(*this);
++(*this); // call the preincrement.
return result;
}
s1& operator++() {
++i;
return *this;
}
// We don't need an operator== now; the default works fine.
T operator* () { return base + i; }
};
s1 begin() {
return s1(4);
}
s1 end() {
s1 result(4);
result.i = 4;
return result;
}
};

#include <stdio.h>
int main() {
top<int> a;
top<int>::s1 b;
for (b = a.begin(); b != a.end(); b++) {
printf("%d\n", *b);
}
}



Now we can fix some style issues:


// Let's give things more accurate names.
template <class T>
class Range { // since we have private data now. :)
// Represents a set of several values (base, base + 1, base + 2, ...).
// For flexibility, we allow constructing a range with any base and size,
// so those need to be data members of the Range:

T base; // also, we're not going to restrict ourselves to ints; we can
// use anything that can be added to.
int count;

public:
// Call the iterator 'iterator', FFS.
struct iterator {
// Now the iterator doesn't remember a base value. Instead, it can
// get it from the iterated-over Range. That means we'll need to store
// a (weak) pointer to it...
Range* parent;
int position;
s1(Range* parent, int position) : parent(parent), position(position) {}
// default copy construction, assignment and equality comparison are still OK.
iterator operator++(int) {
s1 result(*this);
++(*this); // call the preincrement.
return result;
}
iterator& operator++() {
++position;
return *this;
}
// Notice that our particular iterator can be dereferenced if it's
// "past the end". That's ok; undefined behaviour is allowed to "work". ;)
// The client is still NOT allowed to rely on this. :)
T operator* () { return parent->base + position; }
};
iterator begin() {
return iterator(this, 0);
}
iterator end() {
return iterator(this, count);
}

// And a constructor for Ranges...
Range(const T& base, int count) : base(base), count(count) {}
};

// Why not use modern I/O?
#include <iostream>
using std::cout, std::endl;
int main() {
typedef Range<float> frange;
typedef frange::iterator friter;
frange a(3.14, 4);
friter end = a.end();
for (friter it = a.begin(); it != end; ++it) { // prefer preincrement here
cout << *it << endl;
}
}



As for '*b(25)', that only works when T is a type that defines operator()(something convertible from int). :) (Since you are trying to *call* '*b' with 25 as a parameter. Or else, what did you actually mean?)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this