[C++]关于STL慎重选择删除元素的方法

慎重选择删除元素的方法

1 如果你想删除一个连续内容容器的特定值

Container<int> c;
c.erase(remove(c.begin(), c.end(), 1963), c.end());

当c是vector, deque, string时,此方法最好。

对于list

c.remove(1963);

对于关联容器

c.erase(1963);

注意,关联容器里是没有remove成员函数的。

2 如果要删除满足判别式返回true的值

bool badValue(int i);
// If c is vector,string or deque, that is the best way.
c.erase(remove_if(c.begin(), c.end(), badValue), c.end());

// If c is list, use this way instead.
c.remove_if(babValue);

对于关联容器,我们希望有一个循环来遍历所有的元素从而寻找满足条件的值。但这里有一个小问题。

AssocContainer<int> c;
...
for (AssocContainer<int>::iteerator i = c.begin(); i != c.end(); i++) {
    if (badValue(*i)) {
        c.erase(i);  // Tha problem occurs! 
    }
}

这种做法会导致不确定的行为。因为对于关联容器,每次erase后,指向该元素的指针、迭代器、引用全部失效!所以此时,i已经变得无效了。
为了避免这个问题,我们使用一个小技巧。

AssocContainer<int> c;
...
for (AssocContainer<int>::iteerator i = c.begin(); i != c.end(); ) {
    if (badValue(*i)) {
        c.erase(i++);  // Tha problem disappears!
    } else {
        i++;
    }
}

此时问题解决了!

因为i++会返回旧值,也就是说它把i的值给erase,然后在erase执行前,i+1了,于是i指向下一个元素,同时给erase提供了要删除元素的指针。
完美!

3 如果我们希望不仅删除元素,而且还有附属操作。

例如给写入log文件。

对于关联容器就很简单了。

ofstream logFile;
AssocContainer<int> c;
...

for (AssocContainer<int>::iteerator i = c.begin(); i != c.end(); ) {
    if (badValue(*i)) {
        logFile << "Erasing " << *i << "\n";
        c.erase(i++);
    } else {
        i++;
    }
}

但是对于vector,string,deque等,就不能再使用remove_if了,还是要使用循环。但问题又出现了。

对于vector,string,deque,每删除一个元素都会使指向这个元素后面的所有迭代器、指针、引用全部实现!

但,erase会返回一个指针指向下一个元素。
于是乎,问题又解决了。

ofstream logFile;
SeqContainer<int> c;
...

for (SeqContainer<int>::iteerator i = c.begin(); i != c.end(); ) {
    if (badValue(*i)) {
        logFile << "Erasing " << *i << "\n";
        i = c.erase(i);  // i points to next element.
    } else {
        i++;
    }
}

你可能感兴趣的:([C++]关于STL慎重选择删除元素的方法)