Использование итераторов для изменения элементов массива в C ++ - PullRequest
0 голосов
/ 13 сентября 2018

Проблема возникает, когда я пытаюсь написать функцию вставки, которая должна переместить все элементы в массиве вверх в указанное место, заданное итератором, а затем вставить новое значение в массив в положение, заданное итератором..

Код получает ошибки в функции insert со следующей ошибкой:

нет соответствия для оператора [] (типы операндов: 'std:: basic_string [1000] 'и' std :: basic_string ')

Я новичок в использовании итераторов, и я думаю, что невозможно получить доступ к элементам массива с указателями в качестве индексов.Так что я не уверен, есть ли другой способ сделать это, или мне нужно перегрузить оператор [], чтобы он как-то работал?

template <class T>
class Vector {
    public:
        typedef T* iterator;
        Vector () {  }

        T& operator[](unsigned int i) {
           return items[i];
        }
          // T& operator[](iterator i) {
           //return items[*i];
        //}

        iterator begin () {
            return &items[0];
        }
        iterator end () { 
            return &items[used];
        }
        int size () { return used; }

        iterator insert (iterator position, const T& item) { 

            for(Vector<T>::iterator i=&items[998]; i>=position; i--)
            {
                items[*(i+1)]=items[*i];
            }
            items[*position]= item;

            return position;
        }
    private:
        T items[1000];
        int used=0;
};

Ответы [ 4 ]

0 голосов
/ 13 сентября 2018

Посмотрите, как можно реализовать std::move_backward

template< class BidirIt1, class BidirIt2 >
BidirIt2 move_backward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last)
{
    while (first != last) {
        *(--d_last) = std::move(*(--last));
    }
    return d_last;
}

Вам не нужно перемещать какие-либо элементы за end, и мы можем переписать вашinsert будет похоже

iterator insert (iterator position, const T& item) { 
    for(iterator i = end(), d = end() + 1; i != position; )
    {
        *(--d) = std::move(*(--i));
    }

    *position = item;
    ++used;

    return position;
}

Обратите внимание, что это не определено, если вы попытаетесь вставить в полный Vector

0 голосов
/ 13 сентября 2018

В дополнение к ответу Майкл Векслер , я попытался заставить его работать (и, следовательно, нужно немного дольше).

Итак, с его первым предложенным исправлением и дополнительно

items[*position]= item;

изменено на

*position = item;

следующий тест компилируется и запускается:

#include <iostream>

int main()
{
  Vector<double> vec;
  vec.insert(vec.begin(), 1.0);
  vec.insert(vec.begin(), 2.0);
  vec.insert(vec.begin(), 3.0);
  std::cout << "vec.size(): " << vec.size() << '\n';
  for (int i = 0; i < vec.size(); ++i) {
    std::cout << "vec[" << i << "]: " << vec[i] << '\n';
  }
  return 0;
}

Выход:

vec.size(): 0

Oops!

Обновление used также отсутствует в insert():

++used;

А теперь выглядит лучше:

vec.size(): 3
vec[0]: 3
vec[1]: 2
vec[2]: 1

Полный MCVE :

#include <iostream>

template <class T>
class Vector {
    public:
        typedef T* iterator;
        Vector () {  }

        T& operator[](unsigned int i) {
           return items[i];
        }
          // T& operator[](iterator i) {
           //return items[*i];
        //}

        iterator begin () {
            return &items[0];
        }
        iterator end () { 
            return &items[used];
        }
        int size () { return used; }

        iterator insert (iterator position, const T& item) { 

            for(Vector<T>::iterator i=&items[998]; i>=position; i--)
            {
                *(i+1) = *i;
            }
            *position = item;
            ++used;
            return position;
        }
    private:
        T items[1000];
        int used=0;
};

int main()
{
  Vector<double> vec;
  vec.insert(vec.begin(), 1.0);
  vec.insert(vec.begin(), 2.0);
  vec.insert(vec.begin(), 3.0);
  std::cout << "vec.size(): " << vec.size() << '\n';
  for (int i = 0; i < vec.size(); ++i) {
    std::cout << "vec[" << i << "]: " << vec[i] << '\n';
  }
  return 0;
}

Демонстрация в реальном времени на coliru

0 голосов
/ 13 сентября 2018

Таким образом, вы можете думать об итераторе в этом контексте как о прославленном указателе на элементы в массиве, как вы определили в typedef в начале вашего класса.

Когда вы пытаетесь получить доступ к элементам в вашем массиве в функции вставки, вы по существу разыменовываете эти указатели, чтобы получить сами элементы, и ТО, используя эти элементы в качестве индексов для вашего массива, что приводит к ошибке, чтоиндекс неверного типа.

Так, например, предположим, что у вас есть Vector<std::string>.Внутри цикла for в функции вставки у вас есть эта строка:

items[*(i+1)]=items[*i];

Поскольку i является iterator, как вы определили, i имеет тип std::string * и, следовательно, *iимеет тип std::string.Когда вы пишете items[*i], вы пытаетесь использовать std::string в качестве индекса для вашего массива, чего вы не можете сделать.

Вместо этого вы должны использовать строку, подобную следующей:

*(i + 1) = *i

В вашем коде также есть пара логических ошибок, но я оставлю вас, чтобы найти их позже.

Надеюсь, это поможет!

0 голосов
/ 13 сентября 2018

Этот код проблематичен в том смысле, что он создает 1000 элементов типа T, даже если он логически пуст. Кроме того, если имеется более 1000 вставок, верхние элементы отбрасываются.

Что касается проблем компиляции, я пытаюсь скомпилировать код с Vector<int>, и он компилируется нормально, но вылетает. По той же причине он падает с Vector<int>, но не компилируется с Vector<std::string>. Проблема имеет тип *i, то есть std::string в случае Vector<std::string>. Либо используйте итератор полностью, либо используйте индексы, но не смешивайте. Использование итераторов:

        for(Vector<T>::iterator i=&items[998]; i>=position; i--)
        {
            *(i+1)=*i;
        }

Редактировать:

[Только что заметил ответ Шеффа, который понял это после завершения редактирования]

Вышеуказанное вызывает неопределенное поведение для v.insert(v.begin(), value), поскольку i повторяется до items. Чтобы избежать этого, итерация должна прекратиться до того, как она упадет items:

        for(Vector<T>::iterator i=&items[999]; i > position; i--)
        {
            *i = *(i-1);
        }

Также обратите внимание, что строка, следующая за циклом, также должна быть фиксированной:

        items[*position]= item; // <--- BUG: also mixing indexes and iterators


Или используя индексы:
        for(int i= 998; begin() + i>=position; i--)
        {
            items[i+1]=items[i];
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...