使用迭代器修改C ++中的数组元素

时间:2018-09-13 08:48:01

标签: c++ arrays iterator

当我尝试编写一个插入函数时,会出现问题,该函数假定将数组中的所有元素上移到迭代器给定的指定位置,然后在迭代器给定的位置将新值插入到数组中

代码在插入函数中出错,并显示以下错误:

  

“ operator []”不匹配(操作数类型为“ 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 :(得分:2)

此代码在创建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;
        }

编辑:

[在完成此编辑后,刚注意到Scheff的答案就知道了这一点]

由于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];
        }

答案 1 :(得分:1)

除了回答Michael Veksler外,我还尝试使其正常运行(因此需要更长的时间)。

因此,他提出了第一个建议的解决方案,并且

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

糟糕!

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;
}

Live Demo on coliru

答案 2 :(得分:0)

因此,在这种情况下,您可以将迭代器视为指向数组元素的光荣指针,就像您在类开始时在typedef中定义的那样。

当您尝试在insert函数中访问数组中的元素时,实际上是在取消引用这些指针以产生元素本身,然后使用这些元素作为数组的索引来生成THEN,因此产生错误,即索引为类型错误。

例如,假设您有一个Vector<std::string>。在插入函数的for循环内,您具有以下行:

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

因为i是您定义的iterator,所以i的类型为std::string *,因此*i的类型为std::string。然后,当您编写items[*i]时,您将尝试使用std::string作为无法执行的数组索引。

相反,您应该使用类似于以下内容的行:

*(i + 1) = *i

您的代码中也存在一些逻辑错误,但是稍后我将让您查找。

希望这会有所帮助!

答案 3 :(得分:0)

看看如何实现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

中,这是未定义的