I am practicing implementing containers. My goal is to define the iterators begin()
and end()
so that I can have loops in the form of for(auto x : v)
. My container looks like this:
class Vector{
public:
Vector(initializer_list<double> numbers){
sz = numbers.size();
elem = new double[sz];
int i = 0;
for (auto it = numbers.begin(); it!=numbers.end(); ++it)
elem[i++] = *it;
}
~Vector(){delete [] elem;}
double* begin();
double* end();
private:
double* elem;
int sz;
};
Option 1
This is how I have defined the iterators (and they work perfectly fine in my test cases)
double* Vector::begin(){
return elem;
}
double* Vector::end(){
return &elem[sz];
}
Option 2
This is how they are defined in A Tour of C++
double* Vector::begin(){
return &elem[0];
}
double* Vector::end(){
return &elem[0]+sz;
}
My question
As far as I can see both options work fine (assuming the container is non-empty). Does Option 2 have any advantages compared to Option 1 (and vice versa)? I appreciate any suggestions.
While &elem[sz]
and &elem[0]+sz
will wind up giving you the same result on most/all systems, the first is actually undefined behavior. When you do
&elem[sz]
you are actually doing
&*(elem +sz)
and that *
, the dereference, is to an element that doesn't exist. That is undefined behavior per the C++ standard.
With
&elem[0]+sz
you get a pointer to the first element which is legal provided the pointer points to an actual array, and then you advance it to be one past the end. This is a legal and a correct way to get the end iterator provided elem
is not null and points to a valid array.
Another way to do this is to just use
return elem + sz;
as it doesn't require any dereferencing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With