我使用std :: map作为算法的数据持有者但由于某种原因,我需要以某种方式控制map元素的访问。我们知道可以通过直接调用operator [key]来访问地图元素。但是,如果密钥不存在,并且每当您调用operator [key]时,它将创建该密钥,其值自动初始化为“ZERO”。但是在我的算法中,我将通过限制只能在存在键和值非零时修改元素来控制访问。例如,如果地图具有以下元素(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本身而不是map的值类型。
我可以访问所有元素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存储地图的结束迭代器。调用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;
}
有什么想法吗?
答案 0 :(得分:1)
但是如果你在迭代所有元素时修改它,那么循环将永远不会结束,那是什么
然后不要,而是构建一个要删除的对象列表,然后在循环后删除它们。