patterncppModerate
Input iterator in C++
Viewed 0 times
inputiteratorstackoverflow
Problem
For educational purposes and to understand how iterators are working in C++, I've create an input iterator and I would like others to look at and provide any feedback on my code.
References:
template
class iter_input {
public:
typedef T value_type;
typedef T& reference_type;
typedef const T& const_reference_type;
typedef T* pointer_type;
typedef const T* const_pointer_type;
iter_input(pointer_type& pointer) : pointer_(pointer) {}
iter_input(const iter_input& other) : pointer_(other.pointer_) {}
iter_input& operator= (const iter_input& rhs) {
this->pointer_ = rhs.pointer_;
return (*this);
}
iter_input& operator++ (void) {
++this->pointer_;
return (*this);
}
iter_input operator++ (int) {
iter_input temp(*this->pointer_);
++*this;
return (temp);
}
bool operator== (const_reference_type rhs) {
return (this->pointer_ == rhs.pointer_);
}
bool operator!= (const_reference_type rhs) {
return (this->pointer_ != rhs.pointer_);
}
private:
T* pointer_;
};References:
- apache.org
- sgi.com
Solution
Correctness Issues
Needs dereferencing operator
There are two basic operations every iterator needs to support:
Right now, you've covered incrementing, but not dereferencing. That means you can iterate over items, but you can't look at the items themselves, rendering the whole thing nearly useless (I would remove the "nearly", but you can compute the distance between two iterators, and once in a while that's all you really need).
Correct types
These operators should look something like this:
Constructor
The constructor that takes a pointer should take it by value rather than reference. This allows (for example) initializing an iterator from the name of an array:
You can normally take for granted that pointers are cheap to copy, so you don't normally want to pass pointers by reference for the sake of efficiency (but for things like linked lists, you do sometimes want to pass them by reference because you're going to modify the pointer that's passed).
Style Issues
Using
When you return a value from a function, you don't need to enclose that expression in parentheses. Again, this simply adds visual noise and hurts readability without any benefit (and in a few cases that don't apply here can cause other problems as well).
Assignment operator
Unless you need compatibility with older (pre C++11) compilers I'd prefer to define the assignment operator as defaulted rather than including a function body for it.
Use your own typedefs
Instead of
Make it a proper header
If you want to do anything more than a minimal test of this code, you probably want it to be in a header. To facilitate that, you could add the (officially not exactly standard, but almost universally accepted)
Note that if you look at your standard headers, the name they use in place of
Indentation
The 2-space indentation is too small for me to be certain what's supposed to line up with what. The access specifiers (
Needs dereferencing operator
There are two basic operations every iterator needs to support:
- Incrementing the iterator
- Dereferencing the iterator
Right now, you've covered incrementing, but not dereferencing. That means you can iterate over items, but you can't look at the items themselves, rendering the whole thing nearly useless (I would remove the "nearly", but you can compute the distance between two iterators, and once in a while that's all you really need).
reference_type operator *() { return *pointer_; }const correctnessoperator ==() and operator !=() should both be const operators.Correct types
operator== and operator!= should take parameters of type iter_input as their parameters. When you do a comparison, you compare the iterator to another iterator, not the iterator to the type of object the iterator refers to.These operators should look something like this:
bool operator== (iter_input rhs) const {
return pointer_ == rhs.pointer_;
}
bool operator!= (iter_input rhs) const {
return pointer_ != rhs.pointer_;
}Constructor
The constructor that takes a pointer should take it by value rather than reference. This allows (for example) initializing an iterator from the name of an array:
int x[] = {1, 2, 3, 4};
iter_input begin(x);
// or: iter_input begin = std::begin(x);You can normally take for granted that pointers are cheap to copy, so you don't normally want to pass pointers by reference for the sake of efficiency (but for things like linked lists, you do sometimes want to pass them by reference because you're going to modify the pointer that's passed).
Style Issues
this-> considered harmfulUsing
this-> for every reference to a member is (at least in my opinion) a poor idea. It adds visual noise, which hurts readability but provides no benefit.return is an operator, not a functionWhen you return a value from a function, you don't need to enclose that expression in parentheses. Again, this simply adds visual noise and hurts readability without any benefit (and in a few cases that don't apply here can cause other problems as well).
Assignment operator
Unless you need compatibility with older (pre C++11) compilers I'd prefer to define the assignment operator as defaulted rather than including a function body for it.
iter_input& operator= (const iter_input& rhs) = default;Use your own typedefs
Instead of
T *pointer_;, I'd prefer pointer_type pointer_;.Make it a proper header
If you want to do anything more than a minimal test of this code, you probably want it to be in a header. To facilitate that, you could add the (officially not exactly standard, but almost universally accepted)
#pragma once at the beginning, or else add standard "header guards":#ifndef ITER_INPUT_INCLUDED_
#define ITER_INPUT_INCLUDED_
// existing code here
#endifNote that if you look at your standard headers, the name they use in place of
ITER_INPUT_INCLUDED_ will typically start with an underscore. That gives a name that's reserved for the implementation, which means the people writing the compiler can (and in this case should) use that kind of name, but in normal code that's not part of the standard library, you should not use such a name.Indentation
The 2-space indentation is too small for me to be certain what's supposed to line up with what. The access specifiers (
public: and private:) being indented only one space makes this even worse. The days of 40-column displays are long gone. There's no need to skimp on indentation to this degree.Code Snippets
reference_type operator *() { return *pointer_; }bool operator== (iter_input rhs) const {
return pointer_ == rhs.pointer_;
}
bool operator!= (iter_input rhs) const {
return pointer_ != rhs.pointer_;
}int x[] = {1, 2, 3, 4};
iter_input<int> begin(x);
// or: iter_input<int> begin = std::begin(x);iter_input& operator= (const iter_input& rhs) = default;#ifndef ITER_INPUT_INCLUDED_
#define ITER_INPUT_INCLUDED_
// existing code here
#endifContext
StackExchange Code Review Q#121735, answer score: 10
Revisions (0)
No revisions yet.