2017-10-15 4 views
1

J'essaye d'écrire une fonction qui supprime un élément vectoriel de listAccounts en fonction du nom de compte de cet élément vectoriel. Je l'ai écrit:Suppression d'un élément vectoriel d'un type d'objet à l'aide d'un itérateur C++

void Account::remove_account(string name) { 

    auto iter = listAccounts.begin(); 

    for (; iter != listAccounts.end(); iter++) { 
     if ((*iter).account_name == name) { 
      listAccounts.erase(iter); 
     } 
    } 

} 

Mais je reçois une erreur de segmentation de la suppression de vecteur, d'après ce que je comprends, cela signifie que j'ai essayé d'accéder à la mémoire que je n'ai pas accès, mais je ne suis pas sûr comment écrire correctement ceci.

+1

Voulez-vous supprimer un seul élément ou tous les éléments avec la valeur donnée? –

+0

Le duplicata explique que votre for-loop devient invalide après le premier effacement. Vous avez besoin d'un «break» dans l'instruction if. –

+1

@Vlad de Moscou Juste un élément dans le vecteur qui a compte.name égal au nom. –

Répondre

2

Une fois que vous avez effacé l'élément pointé par un itérateur, cet itérateur devient invalide. (pour un std::vector, tous les autres itérateurs après l'élément effacé deviennent également invalides). Et incrémentant ou déréférencement un itérateur non valide a un comportement indéfini.

Vous pouvez faire (en supposant qu'un seul élément doit être supprimé):

void Account::remove_account(string name) { 
    auto iter = std::find_if(listAccounts.begin(), listAccounts.end(), 
       [&](const auto& s){ return s.account_name == name; }); 
    if(iter != listAccounts.end()) 
     listAccounts.erase(iter); 
} 

Pour plusieurs éléments, ce sera:

void Account::remove_account(string name) { 
    for(auto iter = listAccounts.begin(); iter != listAccounts.end();){ 
     iter = std::find_if(iter, listAccounts.end(), 
        [&](const auto& s){ return s.account_name == name; }); 
     if(iter != listAccounts.end()) 
      iter = listAccounts.erase(iter); 
    } 
} 
0

Si vous allez supprimer un seul élément alors vous pouvez écrire

bool Account::remove_account(std::string &name) 
{ 
    auto it = std::find_if(listAccounts.begin(), 
          listAccounts.end(), 
          [&](const auto &item) 
          { 
           return item.account_name == name; 
          }); 

    bool success = it != listAccounts.end(); 

    if (success) listAccounts.erase(it); 

    return success; 
} 

En ce qui concerne votre code puis après cette déclaration

listAccounts.erase(iter); 

l'itérateur devient invalide. Donc vous ne pouvez pas l'incrémenter.

2

Si le conteneur est modifié, l'itérateur devient invalide. Il existe deux bonnes solutions:

void Account::remove_account(const string& name) { 
    auto iter = listAccounts.begin(); 

    while iter != listAccounts.end()) { 
     if (iter->account_name == name) { 
      iter = listAccounts.erase(iter); 
     } else { 
      ++iter; 
     } 
    } 
} 

// or 
void Account::remove_account(const string& name) { 
    listAccounts.erase(
     std::remove_if(std::begin(listAccounts), std::end(listAccounts), 
         [&name](const auto& item) { 
          return item.account_name == name; 
         }), 
     std::end(listAccounts)); 
} 
+0

Dans la deuxième solution, vous appelez 'remove' sur le vecteur. Je pense que vous avez voulu dire "effacer". – navyblue

+0

Oui, vous avez raison, corrigé. –