Odstranění prvku z vektoru uvnitř cyklu for – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Odstranění prvku z vektoru uvnitř cyklu for – C / C++ – Fórum – Programujte.comOdstranění prvku z vektoru uvnitř cyklu for – C / C++ – Fórum – Programujte.com

 

5. 2. 2014   #1
-
0
-

   

for (it = MyVec.begin(); it != MyVec.end(); it++)
{
  if (podminka)
  {
    MyVec.erase(it);
  }
}

Uvedený kód (pochopitelně) nefunguje - vznikne vyjímka. Iterátor se odstraněním prvku z vektoru změní. Jak vyřešit tento problém?

hu

Nahlásit jako SPAM
IP: 195.178.67.–
KIIV
~ Moderátor
+43
God of flame
5. 2. 2014   #2
-
0
-

#1 hlucheucho
mohlo by jit:

it = MyVec.erase(it);
 

(ikdyz ujisti se, aby ti to pak nepreskakovalo prvek za odstranenym)

pripadne   http://en.cppreference.com/…rithm/remove

EDIT2: taky ze to odstranuje spatne.. chce to  it = MyVec.erase(it)-1; nebo ten remove_if  (idealne s lambdou, ale jde to i funkcnim objektem)

Nahlásit jako SPAM
IP: 62.216.147.–
Program vždy dělá to co naprogramujete, ne to co chcete...
KIIV
~ Moderátor
+43
God of flame
5. 2. 2014   #3
-
0
-

+ v c++ se doporucuje prefixova inkrementace a dekrementace (pokud vyslovene neni potreba postinkrementace) jelikoz mohou byt vsechny 4 moznosti pretizene, a postfixove pak zbytecne vytvareji kopie puvodniho objektu - coz sice neni takovej problem u cisla ale u vetsiho objektu by to uz delalo zajimave zpomalovani a tak...

Nahlásit jako SPAM
IP: 62.216.147.–
Program vždy dělá to co naprogramujete, ne to co chcete...
5. 2. 2014   #4
-
0
-

Nerozumím, co chceš říci....   

Ve vektoru mám pointery na instance třídy. 

hu

Nahlásit jako SPAM
IP: 195.178.67.–
KIIV
~ Moderátor
+43
God of flame
5. 2. 2014   #5
-
0
-

#4 hlucheucho
ze bude lepsi pouzit while: 

while (it != MyVec.end()) {
  if (podminka) {
    it = MyVec.erase(it); // posune se na dalsi samo
  } else {
    ++it;                 // posun na dalsi
  }
}

a nebo za pouziti std::remove_if() coz je trosku optimalnejsi verze (jelikoz samo o sobe to jen zkopiruje prvky, ktere nevyhovuji podmince na mista, kde to ma smazat ale pole zustane stejne)

MyVec.erase(
    std::remove_if(
      MyVec.begin(),
      MyVec.end(),
      [](int x){ return x>10 && x<90; }
    ),
    MyVec.end()
);

ale potrebuje to uz c++11 standard kvuli te lambda funkci (a samozrejme todle je jen nad  vector<int> ale bude to fungovat i s pointerem a spravnou podminkou)

Nahlásit jako SPAM
IP: 62.216.147.–
Program vždy dělá to co naprogramujete, ne to co chcete...
5. 2. 2014   #6
-
0
-

Zjištění stavu instance třídy, její likvidaci a odstranění ukazatele z vektoru jsem chtěl dělat v jednom cyklu. Asi to budu muset rozdělit: Zjistit stav instance třídy, zlikvidovat ji a ukazatel nastavit na NULL a v dalším cyklu odstranit ukazatele s hodnotou NULL z vektoru. Pak by fungoval Erase-remove_idiom

hu

Nahlásit jako SPAM
IP: 195.178.67.–
KIIV
~ Moderátor
+43
God of flame
5. 2. 2014   #7
-
0
-

#6 hlucheucho
to pujde i v tom remove_if .. v lambda funkci to neni problem.. staci mit spravne ten datovej typ u x

jen aby to pak nebyl memory leak..  kazdopadne, pokud mas primo tridy v tom vectoru, tak  das trida& x  a pokud je to pointer tak    [](trida * x) { return x->test(); }

Nahlásit jako SPAM
IP: 62.216.147.–
Program vždy dělá to co naprogramujete, ne to co chcete...
vitamin+8
Grafoman
5. 2. 2014   #8
-
0
-

Alebo vseobecnejsie: :)

MyVec.erase(
    std::remove_if(
      MyVec.begin(),
      MyVec.end(),
      [](const decltype(*MyVec.begin())& x){ return /*podmienka*/; }
    ),
    MyVec.end()
);
Nahlásit jako SPAM
IP: 95.105.152.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
5. 2. 2014   #9
-
0
-

další věc, kterou C++ Builder z C++11 nepodporuje   . U 32-bitového překladače to hodně ošidili.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
KIIV
~ Moderátor
+43
God of flame
5. 2. 2014   #10
-
0
-

lambda funkce by to umet melo... ten decltype bych asi pochyboval..  ale neni problem ani kdyby to neumelo lambdu.. staci udelat funktor.. objekt s operatorem ()  

Nahlásit jako SPAM
IP: 62.216.147.–
Program vždy dělá to co naprogramujete, ne to co chcete...
5. 2. 2014   #11
-
0
-

#5 KIIV
cyklus while se osvědčil, akorát mu musí předcházet it = MyVec.begin(); I když se zdá, že je to totéž jako for, chová se to rozdílně - for vždy končí vyjímkou.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
vitamin+8
Grafoman
5. 2. 2014   #12
-
0
-

#11 hlucheucho
erase() vracia prvok ktory nasleduje po prave mazanom prvku. Ak budes mazat posledny prvok vo vectore, tak ti vrati end() iterator a for cyklus ti ho na konci inkrementuje, cize bude ukazovat do niecoho co nasleduje za iteratorom end() a pri dereferencovani ti to zrejme spadne alebo vrati blbost. Inak v c++14 sa lambda da zapisat takto:  [](auto& x){/*...*/}     

Nahlásit jako SPAM
IP: 95.105.152.–
obfuscate: "The cruel god Malloc will strike you down. "
ZMeson: "That's the C god. C++ has a new god. "
5. 2. 2014   #13
-
0
-

C++14 je pro mne sci-fi. C++ Builder C++11 pro 32-bit. Win implementoval jen částečně, pro 64 bitů z velké části. Zatím pracuji na 32-bitových, 64-bitový stroj je jen jeden. Takže pro mne i C++11 není běžnou realitou.

Teď mne napadlo, že for by asi fungoval také, kdyby:

for (it = MyVec.begin(); it != MyVec.end();)
{
  if (podminka) {
    it = MyVec.erase(it); // posune se na dalsi samo
  } else {
    ++it;                 // posun na dalsi
  }
}

Možná srozumitelnější než 

it = MyVec.begin();
while (it != MyVec.end()) {
  if (podminka) {
    it = MyVec.erase(it); // posune se na dalsi samo
  } else {
    ++it;                 // posun na dalsi
  }
}

zítra to můžu testnout, ze zvědavosti

hu

Nahlásit jako SPAM
IP: 188.95.60.–
KIIV
~ Moderátor
+43
God of flame
5. 2. 2014   #14
-
0
-

jen pokud pouzijes knihovni funkce, tak mas daleko vetsi sanci, ze to bude fungovat spravne... coz zrovna ten erase a remove_if jsou.. remove_if neni z noveho standardu, takze bude fungovat pokud mu predas vhodnou funkci, ci funkcni objekt...

proste proc nemit:

class MyClass {
  ...
  static bool podminka(const MyClass * x) { return x->neco == ...; }
};

....

MyVec.erase(
    std::remove_if( MyVec.begin(), MyVec.end(), MyClass::podminka),
    MyVec.end()
);

takhle je to podle me daleko efektnejsi nez se smudlat s cyklama, kde clovek muze a nejspis i udela chybu :D

ikdyz tady je zase pravdepodobne, ze vykouzlis memory leak pokud ty pointery nikde jinde nemas...

Nahlásit jako SPAM
IP: 94.113.93.–
Program vždy dělá to co naprogramujete, ne to co chcete...
6. 2. 2014   #15
-
0
-

Ukazatele nikde jinde nemám. Cykly stejně musí být dva. První naplní množinu soketů (zde lze odstranit objekty s "rozsudkem smrti") a druhý zpracovává události na soketech po návratu funkce select. Objekty udržují přijatá a odeslaná data a stavovou informaci pro komunikaci soketem. V podstatě jde o odstranění objektů po odpojených soketech. Největší problém (překvapivě) nevznikl v destruktoru objektu, ale při odstraňování neplatných ukazatelů z vektoru.

hu

Nahlásit jako SPAM
IP: 195.178.67.–
BDS+3
Věrný člen
11. 2. 2014   #16
-
0
-


#1 hlucheucho
 Uvedený kód (pochopitelně) nefunguje - vznikne vyjímka. Iterátor se odstraněním prvku z vektoru změní. Jak vyřešit tento problém?

Nevím jestli správně, ale já bych zkusil řešit takto:

for (it = MyVec.begin(); it != MyVec.end();)
{
  if (podminka)
  {
    MyVec.erase(it);
  }
  else it++;
}

(Nižší příspěvky jsem nečetl, pokud je má odpověď již mimo, tak se omlouvám.)

Nahlásit jako SPAM
IP: 85.71.83.–
W11 :)
z
~ Anonymní uživatel
268 příspěvků
12. 2. 2014   #17
-
0
-

#16 BDS
Tak si je příště přečti   

Nahlásit jako SPAM
IP: 78.156.159.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 4 hosté

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý