我的问题出在主要功能上。每当我执行remove()时,迭代器都会指向thrash数据。经过调查,我发现问题主要在于。我试图在循环中使用相同的迭代器进行多次删除,即使它编译也不是正确的用法。我将我创建的列表与de std :: list进行了比较,结果发现当你尝试在循环中使用相同的迭代器删除时,std :: list具有相同的输出。
这是我的清单(请忽略评论,它们是葡萄牙语):
template <typename T>
class Lista
{
private:
struct Node
{
Node()
{
prox = NULL;
ant = NULL;
}
Node (T _data)
{
data = _data;
prox = ant = NULL;
}
Node (T _data, Node * _prox, Node * _ant)
{
data = _data;
prox = _prox;
ant = _ant;
}
T data;
Node* prox; //Points to previous element
Node* ant; //Points to next elemente
};
Node* first;
Node* last;
unsigned length=0; //size
public:
//Classe iterador
class iterator
{
public:
friend class Lista<T>;
Node * pNode;
iterator(Node * _pNode)
{
pNode = _pNode;
}
iterator()
{
pNode = NULL;
}
void operator++()
{
if(pNode)
pNode = pNode->prox;
}
void operator--()
{
if(pNode)
pNode = pNode->ant;
}
void operator--(int)
{
if(pNode)
pNode = pNode->ant;
}
void operator++(int)
{
if(pNode)
pNode = pNode->prox;
}
bool operator==(iterator rval)
{
return (pNode == rval.pNode);
}
bool operator!=(iterator rval)
{
return !(pNode == rval.pNode);
}
T operator*()
{
if(pNode)
return pNode->data;
return T();
}
iterator operator+(unsigned _i)
{
iterator iter = *this;
for (unsigned i = 0; i < _i; ++i)
{
if (iter.pNode)
++iter;
else
break;
}
return iter;
}
};
//Classe iterador reverso
class reverse_iterator
{
friend class Lista<T>;
Node * pNode;
reverse_iterator(Node * _pNode)
{
pNode = _pNode;
}
reverse_iterator()
{
pNode = NULL;
}
public:
void operator++()
{
if(pNode)
pNode = pNode->ant;
}
void operator--()
{
if(pNode)
pNode = pNode->prox;
}
void operator--(int)
{
if(pNode)
pNode = pNode->prox;
}
void operator++(int)
{
if(pNode)
pNode = pNode->ant;
}
bool operator!=(reverse_iterator rval)
{
return !(pNode == rval.pNode);
}
bool operator==(reverse_iterator rval)
{
return (pNode == rval.pNode);
}
T operator*()
{
if(pNode)
return pNode->data;
return T();
}
reverse_iterator operator+(int _i)
{
reverse_iterator iter = *this;
for (int i = 0; i < _i; ++i)
{
if (iter.pNode)
++iter;
else
break;
}
return iter;
}
};
//Construtor Padrão
Lista()
{
first = last = NULL;
}
//Contrutor "fill"(veja std::list para detalhes)
Lista(unsigned n, const T& val)
{
first = last = NULL;
for(unsigned i=0; i< n;i++)
push_front(val);
}
//construtor "range"(veja std::list para detalhes)
Lista(iterator inicio, iterator fim)
{
first = last = NULL;
insert(begin(),inicio,fim);
}
//construtor por cópia
Lista(const Lista& l)
{
first = last = NULL;
Node* temp = l.first;
while(temp != NULL)
{
push_back(temp->data);
temp = temp->prox;
}
}
//Destrutor
~Lista()
{
if (!empty())
{
Node * iter = first;
Node * tmp = iter;
while (iter != NULL)
{
tmp = iter;
iter = iter->prox;
delete tmp;
length--;
}
}
}
//Retorna um iterador que aponta para o primeiro elemento da lista
iterator begin()
{
return iterator(first);
}
//Retorna um iterador que aponta para o proximo elemento depois do ultimo("past-the-end")
iterator end()
{
return iterator(NULL); // MUDANÇA AKI: DE LAST->PROX PRA NULL
}
//Retorna um iterador reverso que aponta para o ultimo elemento da lista
reverse_iterator rbegin()
{
return reverse_iterator(last);
}
//Retorna um iterador reverso que aponta para o elemento teórico que antecede o primeior elemnto da lista
reverse_iterator rend()
{
return reverse_iterator(NULL); // MUDANÇA AKI: DE FIRST->ANT PRA NULL
}
//Verifica se a lista está vazia, retornado "true" caso positivo
bool empty()const
{
return (first == last && first == NULL);
}
//Retorna o numero de elementos da lista
unsigned size()const
{
return length;
}
//Retorna uma referência direta para o primeiro elemento da lista(first)
T front()
{
if(first)
{
return first->data;
}
}
//Retorna uma referência direta para o ultimo elemento da lista(last)
T back()
{
if(last)
{
return last->data;
}
}
//Insere um novo elemento(nó) no inicio da lista
void push_front(const T& val)
{
if(!empty())
{
Node* temp = new Node(val);
temp->prox = first;
first->ant = temp;
first = temp;
length++;
}
else
{
Node* temp = new Node(val);
first = last = temp;
length++;
}
}
//Remove e destroi o primeiro elemento(nó) da lista
void pop_front()
{
if(size() == 1)
{
Node* temp = first;
first = last = NULL;
delete temp;
length--;
}
else if (size()>1)
{
Node* temp = first;
first = first->prox;
first->ant = NULL;
delete temp;
length--;
}
}
//Insere um novo elemento(nó) no fim da lista
void push_back(const T& val)
{
if(!empty())
{
Node* temp = new Node(val);
last->prox = temp;
temp->ant = last;
last = temp;
length++;
}
else
{
Node* temp = new Node(val);
first = last = temp;
length++;
}
}
//Remove e destroi o ultimo elemento(nó) da lista
void pop_back()
{
if(size() ==1)
{
Node* temp = last;
first = last = NULL;
delete temp;
length--;
}
else if(size()>1)
{
Node* temp = last;
last = last->ant;
last->prox = NULL;
delete temp;
length--;
}
}
//Insert "single element"(veja std::list para detalhes)
iterator insert(iterator position,const T&val)
{
if(!empty())
{
if(position != begin() && position != end())
{
Node* temp = new Node(val);
for(iterator it = begin();it!=end();it++)
{
if(it.pNode->prox == position.pNode)
{
it.pNode->prox = temp;
temp->ant = it.pNode;
temp->prox = position.pNode;
position.pNode->ant = temp;
length++;
return iterator(temp);
}
}
}
else
{
if(position == begin())
{
push_front(val);
return iterator(first);
}
else if (position == end())
{
push_back(val);
return iterator(last);
}
}
}
push_front(val);
return iterator(first);
}
//Insert "fill"(veja std::list para detalhes)
void insert (iterator position, unsigned n, const T& val)
{
iterator it = position;
while(n)
{
it = insert(it,val);
n--;
}
}
//Insert "range"(veja std::list para detalhes)
void insert (iterator position, iterator primeiro, iterator ultimo)
{
if(position != NULL)
{
if(ultimo != end() && primeiro != end())
{
iterator it = position;
while( primeiro != ultimo)
{
it = insert(it,*ultimo);
ultimo--;
}
it = insert(it,*primeiro);
}
else if( ultimo == end() && primeiro != end())
{
ultimo = primeiro;
iterator it = position;
do
{
ultimo++;
}while(ultimo.pNode->prox);
while( primeiro != ultimo)
{
it = insert(it,*ultimo);
ultimo--;
}
it = insert(it,*primeiro);
}
}
else
{
first = last = NULL;
if(primeiro.pNode != NULL && ultimo.pNode != NULL)
{
while(primeiro != ultimo)
{
push_front(*ultimo);
ultimo--;
}
push_front(*primeiro);
}
else
{
if(ultimo.pNode == NULL && primeiro.pNode != NULL)
{
ultimo = primeiro;
do
{
ultimo++;
}while(ultimo.pNode->prox);
while( primeiro != ultimo)
{
push_front(*ultimo);
ultimo--;
}
push_front(*primeiro);
}
}
}
}
//Remove um único elemento(nó) de determinada posição da lista,retornando um iterador que aponta para o elemento seguinte
//aquele removido/destruido por ultimo.
iterator erase (iterator position)
{
if(!empty())
{
if(position != end())
{
if(size() == 1)
{
pop_front();
return end();
}
else
{
iterator it = begin();
while(it != end())
{
if(it == position)
{
if(position != begin() && position.pNode != last) //MUDANÇA: position != end() para position.pNode != last
{
Node* temp = position.pNode->ant;
position++;
temp->prox = position.pNode;
position.pNode->ant = temp;
delete it.pNode;
length--;
return position;
}
else
{
if(position == begin())
{
//Node* temp = first; //MUDANÇA: Tirou o novo nó
position = it.pNode->prox; //MUDANÇA: position = temp->prox; para position = it.pNode->prox;
first = position.pNode;
first->ant = NULL; //ADICIONADO
delete it.pNode; //MUDANÇA: delete tempo para delete it.pNOde
length--;
return position;
}
else if(position.pNode == last) //MUDANÇA: position != end() para position.pNode != last
{
//Node* temp = last; //MUDANÇA: Tirou o novo nó
position = end(); //MUDANÇA: position = temp->prox para position = end()
last = it.pNode->ant; //MUDANÇA: last = position.pNode para last = it.pNode->ant
last->prox = NULL; //ADICIONADO
delete it.pNode; //MUDANÇA: delete tempo para delete it.pNOde
length--;
return position;
}
}
}
it++;
}
}
}
else
return end();
}
else
return end();
}
//Remove todos elementos(nós) de um intervalo da lista(inclusive o apontado por "primeiro" e exclusive o apontado por "ultimo"),
//retornando um iterador que aponta para o elemento seguinte aquele removido/destruido por ultimo.
iterator erase (iterator primeiro, iterator ultimo)
{
if(ultimo.pNode)
{
for(iterator it = primeiro; it != ultimo;)
it = erase(it);
return ultimo;
}
else
{
iterator itaux = begin()+(size()-1);
for(iterator it = primeiro;it!=itaux;)
it = erase(it);
return ultimo;
}
}
//Remove da lista todos os elementos(nós) cujo conteúdo se compara igualmente com "val"
iteratorvoid remove (const T& val)
{
for(iterator it = begin();it != end();)
{
if(*it == val)
it = erase(it);
else
it++;
}
}
//Inverte a ordem dos elementos(nós) da lista
void reverse()
{
if(empty() || size() == 1)
return;
else
{
Node* temp1 = first;
Node* temp2 = temp1->prox;
temp1->prox = NULL;
temp1->ant = temp2;
while(temp2 != NULL)
{
temp2->ant = temp2->prox;
temp2->prox = temp1;
temp1 = temp2;
temp2 = temp2->ant;
}
last = first;
first = temp1;
}
}
};
这是主要的(请忽略评论,它们是葡萄牙语):
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <list>
#include "Lista.h" // ------ ALTERAR AQUI
#define N 500
typedef Lista<int> lista_ref_type;
//typedef std::list< int > lista_ref_type;
typedef std::list< int > lista_type;
void compare( lista_type &lista, lista_ref_type &lista_ref ) {
lista_type::iterator it = lista.begin();
lista_ref_type::iterator it_ref = lista_ref.begin();
while( it_ref != lista_ref.end() ) {
assert( it != lista.end() );
assert( *it == *it_ref);
it++;
it_ref++;
}
assert( it == lista.end() );
return;
}
int main() {
lista_ref_type lista_ref;
lista_type lista;
srand( time(NULL) );
assert( lista_ref.size() == lista.size() );
assert( lista_ref.empty() == lista.empty() );
for( int i=0; i<N; i++) {
int valor = rand();
if( valor/RAND_MAX > 0.5 ) {
lista_ref.push_back(valor);
lista.push_back(valor);
} else {
lista_ref.push_front(valor);
lista.push_front(valor);
}
assert( lista_ref.size() == lista.size() );
assert( lista_ref.empty() == lista.empty() );
}
compare( lista, lista_ref);
std::cout << "Etapa 1: OK!" << std::endl;
for( int i=0; i<N; i++) {
assert( lista_ref.size() == lista.size() );
assert( lista_ref.empty() == lista.empty() );
assert( lista_ref.front() == lista.front() );
assert( lista_ref.back() == lista.back() );
int valor1 = rand()%lista.size();
lista_type::iterator it = lista.begin();
lista_ref_type::iterator it_ref = lista_ref.begin();
while(valor1) {
assert( it_ref != lista_ref.end() );
assert( it != lista.end() );
assert( *it == *it_ref);
it++;
it_ref++;
valor1--;
}
assert( *it == *it_ref);
//lista.remove( *it ); //THE PROBLEM IS HERE. I CANT CALL REMOVE(*IT) IN THIS LOOP
//lista_ref.remove( *it_ref ); //THE PROBLEM IS HERE. I CANT CALL REMOVE(*IT) IN THIS LOOP
}
//assert( lista.empty() );
//assert( lista_ref.empty() );
std::cout << "Etapa 2: OK!" << std::endl;
for( int i=0; i<N; i++) {
int valor = rand();
if( valor/RAND_MAX > 0.5 ) {
lista_ref.push_back(valor);
lista.push_back(valor);
} else {
lista_ref.push_front(valor);
lista.push_front(valor);
}
assert( lista_ref.size() == lista.size() );
//assert( lista_ref.empty() == lista.empty() );
}
compare( lista, lista_ref);
std::cout << "Etapa 3: OK!" << std::endl;
lista.reverse();
lista_ref.reverse();
compare( lista, lista_ref);
std::cout << "Etapa 4: OK!" << std::endl;
for( int i=0; i<N; i++) {
assert( lista_ref.size() == lista.size() );
//assert( lista_ref.empty() == lista.empty() );
assert( lista_ref.front() == lista.front() );
assert( lista_ref.back() == lista.back() );
int valor = rand();
if( valor/RAND_MAX > 0.5 ) {
lista_ref.pop_back();
lista.pop_back();
} else {
lista_ref.pop_front();
lista.pop_front();
}
}
//assert( lista.empty() );
//assert( lista_ref.empty() );
std::cout << "Etapa 5: OK!" << std::endl;
for( int i=0; i<N; i++) {
assert( lista_ref.size() == lista.size() );
int valor1 = rand()%(lista.size()+1);
int valor2 = rand();
if(valor1 == lista.size())
valor1 = 0;
lista_type::iterator it = lista.begin();
lista_ref_type::iterator it_ref = lista_ref.begin();
while( it_ref != lista_ref.end() && valor1) {
assert( it != lista.end() );
assert( *it == *it_ref);
it++;
it_ref++;
valor1--;
}
lista.insert( it, valor2);
lista_ref.insert( it_ref, valor2);
}
compare( lista, lista_ref);
std::cout << "Etapa 6: OK!" << std::endl;
for( int i=0; i<N; i++) {
assert( lista_ref.size() == lista.size() );
int valor1 = rand()%lista.size();
int valor2 = rand();
lista_type::iterator it = lista.begin();
lista_ref_type::iterator it_ref = lista_ref.begin();
while(valor1) {
assert( it_ref != lista_ref.end() );
assert( it != lista.end() );
assert( *it == *it_ref);
it++;
it_ref++;
valor1--;
}
lista.erase( it);
lista_ref.erase( it_ref );
}
//assert( lista.empty() );
//assert( lista_ref.empty() );
std::cout << "Etapa 7: OK!" << std::endl;
std::cout << "UFA!" << std::endl;
return 0;
}
答案 0 :(得分:2)
在删除之前,您需要将迭代器推进到您要移除的元素之外。
像(未经测试)
之类的东西 for(iterator it = begin();it != end();)
{
iterator current = it++;
if(*current == val)
erase(current);
}
或者,当然,使用库算法http://www.sgi.com/tech/stl/remove_if.html
答案 1 :(得分:0)
对于仅删除第一个项目的特定情况,保证至少剩余一个项目,您所要做的就是在删除之前移动迭代器。
但是,一般来说,你甚至不知道迭代器可以引用的是否还有任何项目。
因此,对于一般情况,你必须决定你想要什么,并考虑没有剩下的情况。