1

オブジェクトのプロパティの 1 つが条件に一致する場合、オブジェクトのリストから要素を削除しようとしています。これは私の機能ですが、この操作を実行してから内容を印刷した後、erase() は効果がないようです。ここで何が間違っていますか?

void FileReader::DeleteProcess(int id, list<Process> listToDeleteFrom)
{
    list<Process>::iterator process;

    for(process = listToDeleteFrom.begin(); process != listToDeleteFrom.end(); process++)
    {
        if (process -> ID == id)
        {
            listToDeleteFrom.erase(process);
        }
    }
}
4

3 に答える 3

11

まず、参照によってリストを渡す必要があります。コードはコピーで機能しているため、コードを変更しても発信者のリストには影響しません。

void FileReader::DeleteProcess(int id, list<Process> & listToDeleteFrom)
                                                     ^

次に、リスト要素を消去すると、その要素を参照するイテレータが無効になるため、後で反復を続行しようとすると、未定義の動作が発生します。erase削除する要素が1つしかない場合は、 ;を呼び出した直後に関数から戻ります。それ以外の場合、ループは次のように構造化する必要があります。

for (auto it = list.begin(); it != list.end(); /* don't increment here */) {
    if (it->ID == id) {
        it = list.erase(it);
    } else {
        ++it;
    }
}
于 2012-10-01T02:31:25.027 に答える
6

erase()イテレータが を繰り返し処理しているときに呼び出すと、イテレータがlist無効になります。消去する要素を 2 番目のリストに追加してから、それらを削除します。

また、参照やポインターを使用するのではなく、値でリストを渡していることに注意してください。またはを使用するつもりでしたlist<Process>& listToDeleteFromlist<Process>* listToDeleteFrom?

于 2012-10-01T02:27:13.343 に答える
1

変更が反映されていないことがわかる理由は、リストが参照によって渡されていないため、リストのコピーから要素を削除しているだけだからです。

これに変更します:

void FileReader::DeleteProcess(int id, list<Process> &listToDeleteFrom) //note &

これにより、関数内で同じ構文が維持され、元の構文が変更されます。

ただし、要素を削除する方法は少し最適ではありません。C ++ 11を使用している場合、以下は無効化の問題を取り除き、ジョブ用に設計された既存のアルゴリズムを使用して、より慣用的なものになります。

listToDeleteFrom.erase ( //erase matching elements returned from remove_if
    std::remove_if( 
        std::begin(listToDeleteFrom), 
        std::end(listToDeleteFrom), 
        [](const Process &p) { //lambda that matches based on id
            return p->ID == id;
        }
    ),
    std::end(listToDeleteFrom) //to the end of the list
);

std::list<>::erase一致する要素を実際に消去するために、そこに保持することに注意してください。これは、消去-削除イディオムとして知られています。

于 2012-10-01T02:35:13.403 に答える