c++ - 征求关于自定义迭代器的建议我在 C++ 中自定义的容器

标签 c++ reference iterator

我使用 std::map 作为我算法的数据容器,但出于某种原因,我需要以某种方式控制 map 元素的访问。我们知道可以通过直接调用 operator[key] 来访问 map 的元素。但是,如果 key 不存在,并且每当您调用 operator[key] 时,它都会自动创建该 key ,并将其值初始化为“零”。但是在我的算法中,我将通过限制只能在存在键且值不为零时修改元素来控制访问。例如,如果 map 有以下元素(3, 2),(1, 0),(4, 0),(2, 7),则只能修改(3,2)和(2,7)。我知道我可以在修改元素之前的任何地方使用 map::find(key) 或 map::count(key) 添加一些代码,但是它太多了所以我想如下编写自己的容器

class MyContainer;

template <typename T> class myiterator :public iterator<forward_iterator_tag, T>
{
  friend class MyContainer;
  private:
    T *pointer;
    myiterator(T *pointer):pointer(pointer) {}

  public:
    T& operator*() {return (*pointer);}

    const myiterator<T>& operator++()
    {
      pointer->current_iterator++;
  return *this;
    }

    bool operator!=(const myiterator<T>& other) const
    {
      return pointer->current_iterator != other.pointer->current_iterator;
    }

    bool isEnd(void) const
    {
      return pointer->current_iterator == pointer->end_iterator;
    }
  };

  class MyContainer
  {
    friend class myiterator<MyContainer>;
    public:
      typedef myiterator<MyContainer> iterator;

    private:
      map<int, int> data;
      map<int, int>::iterator current_iterator, end_iterator;

    public:
      MyContainer() {current_iterator = data.begin(); }

      void addDataPair(int key, int value) {data[key] = value;}

      int first() {return (*current_iterator).first;}
      int second() {return (*current_iterator).second;}

      // initialize the current_iterator to the begin of the data (map) and set the end iterator too
      iterator begin() 
      {
        current_iterator = data.begin();
        end_iterator = data.end();
        return myiterator<MyContainer>(this);
      }

      // return the container w/ current_iterator point to where the key is
      MyContainer &operator[](int key)
      {
        current_iterator = data.find(key);
        return (*this);
      }

      // only increase the value by one when the key does exist and with initial value non-zero
      void operator++(void)
      {
        if ( (current_iterator != data.end()) && 
           ((*current_iterator).second>0) ) 
        {
          ((*current_iterator).second)++;
        }
      }
   };

如您所见,我没有使用 map::iterator,而是从 std::iterator 继承了一个迭代器,这样迭代器引用 MyContainer 本身而不是映射的值类型。我可以通过

访问所有元素
MyContainer h;

h.addDataPair(1, 3);
h.addDataPair(2, 4);
h.addDataPair(3, 0);
h.addDataPair(7, 9);
h.addDataPair(11, 2);

for (MyContainer::iterator it=h.begin(); !it.isEnd(); ++it)
{
  cout << (*it).first() << " " << (*it).second() << endl;
}

有了这个想法,每当循环迭代器时,它都会返回容器的引用,因此我可以添加一些代码(如 operator[]、operator++)来控制更新 map 元素的行为。例如,在这段代码中,

void operator++(void)

将忽略对不存在的键或值初始化为零的元素的任何操作。但是代码中还有一些疑惑,正在寻找大家的建议

1) 如果你仔细阅读代码,你会看到我使用 current_iterator 来存储当前的 map::iterator,并使用 end_iterator 来存储 map 的结束迭代器。这些迭代器将在调用 MyContainer.begin() 时设置。我需要 end_iterator 的原因是,如果我将 current_iterator 设置为 map.end() 那么,它将在循环期间更改 current_iterator。例如,下面的代码将不起作用

iterator begin() 
{
  current_iterator = data.begin();
  return myiterator<MyContainer>(this);
}

iterator end() 
{
  current_iterator = data.end();   // here we set current_iterator as data.end(), but this will change the current iterator of data too
  return myiterator<MyContainer>(this);
}

所以当你用下面的代码循环容器时,它不会正确运行

for (MyContainer::iterator it=h.begin(); it!=h.end(); ++it)
{
  cout << (*it).first() << " " << (*it).second() << endl;
}

这就是我在迭代器中编写 isEnd() 函数的原因。但这看起来并不优雅,有没有更好的办法来解决这个问题?

2) 对于“有限”++ 操作,如果我们如下修改容器中的 map 元素,则没有任何问题

// assuming the map initially contains (2, 4), (3, 0), (7, 9), (11, 2)

h[4]++; // modify the element with key==4, won't do anything, no such key
h[3]++; // modify the element with key==3, won't do anything, value=0
h[11]++; // modify the element with key==11, then we have (11, 3)
(*(h.begin()))++; // modify the first element, works, we have (2,5)

但是如果你在迭代所有元素的同时修改它,循环将永远不会结束,这是为什么

for (MyContainer::iterator it=h.begin(); !it.isEnd(); ++it)
{
  (*it)++;    // it works
  (*it)[3]++; // it will cause the loop run and never stop
  cout << (*it).first() << " " << (*it).second() << endl;
}

有什么想法吗?

最佳答案

But if you modify that while iterating all elements, the loop will never end, what's that

那就不要,而是构建一个要删除的对象列表,然后在循环后删除它们。

关于c++ - 征求关于自定义迭代器的建议我在 C++ 中自定义的容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10237858/

相关文章:

c++ - 改变字符指针的值

arrays - 散列 perl 值中的数组

具有缓存层的 Java 对象引用

c++ - std::reverse_iterator 奇怪的行为(UB?)

javascript - 如何重置迭代器?

c++ - 自动返回类型匹配 void

c++ - 使用 C++ 实例变量归档/序列化 Objective-C 对象

python - Python 中的引用问题(树)

c++ - 在 C++ 中迭代列表并搜索另一个列表中的每个元素

c++ - 虚函数间共享代码