std::목록을 반복하는 동안 목록에서 요소를 제거할 수 있습니까?
다음과 같은 코드가 있습니다.
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
다시 목록을 읽지 않도록 업데이트 후 바로 비활성 항목을 삭제했으면 합니다.행을 하면 ,, 멘, 코, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, 러, when, when, when, , when, but, but, but, , 이렇게i++
" not : '이렇게 하면 안 돼요.' 해서 '증가하지 .for 스테이트먼트에서 증가하지 않는 대체 방법을 시도해 봤지만, 아무 것도 효과가 없었습니다.
표준:: 목록을 이동할 때 항목을 삭제하는 가장 좋은 방법은 무엇입니까?
먼저 (i++를 사용하여) 반복기를 증가시킨 다음 이전 요소를 제거해야 합니다(예: i++에서 반환된 값을 사용).다음과 같이 코드를 while loop으로 변경할 수 있습니다.
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i++); // alternatively, i = items.erase(i);
}
else
{
other_code_involving(*i);
++i;
}
}
다음 작업을 수행합니다.
i= items.erase(i);
그러면 제거한 반복기 이후의 위치를 가리키도록 반복기가 올바르게 업데이트됩니다.
Kristo의 답변과 MSN의 답변을 조합해야 합니다.
// Note: Using the pre-increment operator is preferred for iterators because
// there can be a performance gain.
//
// Note: As long as you are iterating from beginning to end, without inserting
// along the way you can safely save end once; otherwise get it at the
// top of each loop.
std::list< item * >::iterator iter = items.begin();
std::list< item * >::iterator end = items.end();
while (iter != end)
{
item * pItem = *iter;
if (pItem->update() == true)
{
other_code_involving(pItem);
++iter;
}
else
{
// BTW, who is deleting pItem, a.k.a. (*iter)?
iter = items.erase(iter);
}
}
물론, 가장 효율적이고 SuperCool® STL에 적합한 것은 다음과 같습니다.
// This implementation of update executes other_code_involving(Item *) if
// this instance needs updating.
//
// This method returns true if this still needs future updates.
//
bool Item::update(void)
{
if (m_needsUpdates == true)
{
m_needsUpdates = other_code_involving(this);
}
return (m_needsUpdates);
}
// This call does everything the previous loop did!!! (Including the fact
// that it isn't deleting the items that are erased!)
items.remove_if(std::not1(std::mem_fun(&Item::update)));
요약하면 다음과 같은 세 가지 방법이 있습니다.
사용법 1. 사용법while
list<int> lst{4, 1, 2, 3, 5};
auto it = lst.begin();
while (it != lst.end()){
if((*it % 2) == 1){
it = lst.erase(it);// erase and go to next
} else{
++it; // go to next
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
2. 사용방법remove_if
"이것들"은 다음과 같습니다.
list<int> lst{4, 1, 2, 3, 5};
lst.remove_if([](int a){return a % 2 == 1;});
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
3. 사용방법std::remove_if
와 fun with 와 결합된 erase
버버: :
list<int> lst{4, 1, 2, 3, 5};
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
return a % 2 == 1;
}), lst.end());
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
4. 사용방법for
해야 합니다.loop、 loop 、 음음음 、 음음음 loop loop loop loop loop 。
list<int> lst{4, 1, 2, 3, 5};
for(auto it = lst.begin(); it != lst.end();++it){
if ((*it % 2) == 1){
it = lst.erase(it); erase and go to next(erase will return the next iterator)
--it; // as it will be add again in for, so we go back one step
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
std::remove_if
알고리즘.
★★★★
컬렉션 관련 작업은 다음과 같습니다.
- 수집품을 준비하다
- 프로세스 수집
이 단계를 섞지 않으면 생활이 더 편해질 것이다.
std::remove_if
★★★list::remove_if
(하고 있는 있는TCollection
)std::for_each
Kristo의 대답에 대한 루프 버전 대안.
효율이 떨어지면 삭제할 때 뒤로 갔다가 다시 앞으로 갑니다.단, 추가 반복 인크리먼트의 대가로 루프 스코프에서 반복기를 선언하고 코드를 조금 더 깔끔하게 표시할 수 있습니다.무엇을 선택할지는 그 순간의 우선순위에 따라 달라집니다.
그 대답은 완전히 시간에서 벗어난 거였어, 나도 알아...
typedef std::list<item*>::iterator item_iterator;
for(item_iterator i = items.begin(); i != items.end(); ++i)
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i--);
}
else
{
other_code_involving(*i);
}
}
는 ''를 입니다.for
목록을 반복하고 목록 트래버설 중에 항목이 삭제되었을 때 반복기를 증가 또는 재검증하는 루프입니다.
for(auto i = items.begin(); i != items.end();)
{
if(bool isActive = (*i)->update())
{
other_code_involving(*i);
++i;
}
else
{
i = items.erase(i);
}
}
items.remove_if(CheckItemNotActive);
제거는 제거된 요소를 가리키는 반복기만 비활성화합니다.
따라서 이 경우 *i를 삭제한 후 i는 무효가 되어 인크리먼트를 실행할 수 없습니다.
삭제할 요소의 반복기를 먼저 저장한 후 반복기를 늘린 다음 저장된 반복기를 삭제합니다.
생각나면std::list
큐와 같이 보관하는 모든 항목을 큐를 해제하고 큐를 넣을 수 있지만 삭제할 항목만 큐를 해제할 수 있습니다(큐를 해제할 수 없습니다).이 예에서는 1~10의 숫자를 포함하는 목록에서 5를 삭제합니다.
std::list<int> myList;
int size = myList.size(); // The size needs to be saved to iterate through the whole thing
for (int i = 0; i < size; ++i)
{
int val = myList.back()
myList.pop_back() // dequeue
if (val != 5)
{
myList.push_front(val) // enqueue if not 5
}
}
myList
이제 1-4와 6-10의 숫자만 갖게 됩니다.
뒤로 반복하면 통과할 나머지 요소의 요소가 지워지는 효과를 피할 수 있습니다.
typedef list<item*> list_t;
for ( list_t::iterator it = items.end() ; it != items.begin() ; ) {
--it;
bool remove = <determine whether to remove>
if ( remove ) {
items.erase( it );
}
}
PS: 예를 들어, 역방향 반복에 대해서는, 이것을 참조해 주세요.
PS2: 끝부분의 소거 요소가 잘 처리되는지 철저히 테스트하지 않았습니다.
쓸 수 있다
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive) {
i = items.erase(i);
} else {
other_code_involving(*i);
i++;
}
}
다음과 같이 동등한 코드를 작성할 수 있습니다.std::list::remove_if
보다 장황하고 명료한 표현입니다.
items.remove_if([] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
});
그std::vector::erase
std::remove_if
idio는 아이템이 O(n)에서 콤플렉스를 유지하기 위해 리스트가 아닌 벡터일 경우 또는 범용 코드를 쓰고 아이템이 단일 아이템을 지우는 효과적인 방법이 없는 컨테이너일 경우 사용합니다(벡터 등).
items.erase(std::remove_if(begin(items), end(items), [] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
}));
루프를 실행하는 동안 유연하고 빠르고 읽기 및 쓰기가 쉽습니다.
auto textRegion = m_pdfTextRegions.begin();
while(textRegion != m_pdfTextRegions.end())
{
if ((*textRegion)->glyphs.empty())
{
m_pdfTextRegions.erase(textRegion);
textRegion = m_pdfTextRegions.begin();
}
else
textRegion++;
}
제 방법을 공유하겠습니다.이 메서드는 반복 중에 목록 뒤에 요소를 삽입할 수도 있습니다.
#include <iostream>
#include <list>
int main(int argc, char **argv) {
std::list<int> d;
for (int i = 0; i < 12; ++i) {
d.push_back(i);
}
auto it = d.begin();
int nelem = d.size(); // number of current elements
for (int ielem = 0; ielem < nelem; ++ielem) {
auto &i = *it;
if (i % 2 == 0) {
it = d.erase(it);
} else {
if (i % 3 == 0) {
d.push_back(3*i);
}
++it;
}
}
for (auto i : d) {
std::cout << i << ", ";
}
std::cout << std::endl;
// result should be: 1, 3, 5, 7, 9, 11, 9, 27,
return 0;
}
거기에 버그가 있는 것 같은데, 나는 이렇게 코드화한다:
for (std::list<CAudioChannel *>::iterator itAudioChannel = audioChannels.begin();
itAudioChannel != audioChannels.end(); )
{
CAudioChannel *audioChannel = *itAudioChannel;
std::list<CAudioChannel *>::iterator itCurrentAudioChannel = itAudioChannel;
itAudioChannel++;
if (audioChannel->destroyMe)
{
audioChannels.erase(itCurrentAudioChannel);
delete audioChannel;
continue;
}
audioChannel->Mix(outBuffer, numSamples);
}
언급URL : https://stackoverflow.com/questions/596162/can-you-remove-elements-from-a-stdlist-while-iterating-through-it
'programing' 카테고리의 다른 글
데이터베이스에 저장된 모든 프로시저에 대해 사용자에게 실행 권한을 부여하시겠습니까? (0) | 2023.04.16 |
---|---|
문자열 단어를 반복하려면 어떻게 해야 하나요? (0) | 2023.04.16 |
이중 괄호 또는 단일 괄호, 괄호, 컬리 괄호 사용 방법 (0) | 2023.04.16 |
시트가 있는지 테스트 또는 확인 (0) | 2023.04.16 |
SQL Server 2005 데이터베이스에서 어떤 테이블이 가장 많은 공간을 차지하는지 어떻게 알 수 있습니까? (0) | 2023.04.16 |