0

After reading this code to teach how a simple vector of doubles is built:

class vector
{
    int sz;
    double* elem;

public:
    vector(int s)
        :sz{s}, elem{new double[sz]}
    {
        for (int i = 0; i < sz; ++i)elem[i] = 0.0;
    }
    vector(initializer_list<double>lst)
        :sz{ int(lst.size()) }, elem{ new double[sz] }
    {
        copy(lst.begin(), lst.end(), elem);
    }
    vector(const vector&);
    ~vector(){ delete[] elem; }
    double get(int n) const { return elem[n]; }
    void set(int n, double v) { elem[n] = v; }
};

The copy constructor is defined as:

vector::vector(const vector& arg)
    :sz{ arg.sz }, elem{new double[arg.sz]}
{
    copy(arg.elem, arg.elem + sz, elem);
}

Shouldn't the range arg.elem, arg.elem + sz be actually

arg.elem, arg.elem + sz - 1

?

TosinAl
  • 137
  • 1
  • 9
  • 1
    Why do you think that? –  Mar 10 '18 at 18:54
  • 3
    Normally the end of range is NOT inclusive, while the beginning is. This allows you to pass empty ranges. – HolyBlackCat Mar 10 '18 at 18:54
  • @NeilButterworth Because arg.elem + sz looks like it's passing an extra empty elem to the range. I think arg.elem implied elem[0] while arg.elem + sz implies elem[sz]. – TosinAl Mar 10 '18 at 19:00

2 Answers2

1

In C++ various functions accept a beginning iterator or pointer, and an end iterator or pointer. The beginning iterator is included in whatever operation it is, be it copy or sort or whatever, but the end iterator or pointer is not included. Usually the operation is start iterator to (end iterator - 1). From the docs for std::copy:

Input iterators to the initial and final positions in a sequence to be copied. The range used is [first,last), which contains all the elements between first and last, including the element pointed by first but not the element pointed by last.

That's why in the containers the end() iterator doesn't point to the last element. std::vector::end() is an iterator to one past the last member for example.

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
0

std::copy is implemented as something like:

template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last, 
              OutputIt d_first)
{
    while (first != last) {
        *d_first++ = *first++;
    }
    return d_first;
}

the element pointed to by last is not copied. If it was then the following code:

std::vector<int> in;
std::vector<int> out;
std::copy(in.begin(), in.end(), std::back_inserter(out.begin()))

wouldn't work. You'd have to do something like this which wouldn't work in the case of an empty vector:

std::vector<int> in;
std::vector<int> out;
std::copy(in.begin(), in.end() - 1, std::back_inserter(out.begin()))
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60