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
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
#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)
+ 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...
Nerozumím, co chceš říci....
Ve vektoru mám pointery na instance třídy.
hu
#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)
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
#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(); }
Alebo vseobecnejsie: :)
MyVec.erase(
std::remove_if(
MyVec.begin(),
MyVec.end(),
[](const decltype(*MyVec.begin())& x){ return /*podmienka*/; }
),
MyVec.end()
);
další věc, kterou C++ Builder z C++11 nepodporuje . U 32-bitového překladače to hodně ošidili.
hu
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 ()
#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){/*...*/}
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
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...
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
#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.)
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku