如何正确使用std:vector的erase()函数?

3

在使用std:vector的erase()函数时,我遇到了一个奇怪的问题。 我使用以下代码:

int count = 0;
for (int itr=0; itr<b.size(); ++itr) {
    if (b[count].notEmpty = false) {
        b.erase(b.begin()+count);
        --count;
    }
    ++count;
}

然而,由于某种原因实际上没有元素被从b中删除。b在其他地方声明如下:
vector<block_data> b;

其中block_data是一个结构体,包含了布尔值notEmpty。在代码的早期部分,一些b的元素已经被正确地赋值为notEmpty = false,因此我不确定它们为什么没有被清除。这是语法错误还是其他问题?


1
值得一提的是,测试!x.notEmpty(x不是非空)的双重否定逻辑表明您应该将notEmpty重命名为empty - Jon Purdy
3个回答

8

您使用erase没有问题。问题在于if条件语句内的赋值:

if(b[count].notEmpty = false)

这段代码将b[count].notEmpty设置为false,然后返回false。这将导致if语句的内部代码永远不会执行。
请将其改为:
if(b[count].notEmpty == false)

或事件
if(!b[count].notEmpty)

您应该准备就绪。


+1 哈哈,我看了一下原帖的代码,完全没注意到作业的要求。 - salezica
2
@Mike N.:不用担心,这是一个非常常见的问题。尝试打开编译器警告,因为大多数编译器确实会针对这种特殊情况提供警告。 - Peter Alexander

3

其他人已经指出了如何修复您的代码,但是以防万一:如何使用标准算法。

// Decide if an element is to be removed
auto predicate = [](block_data& b)
{
    // more idiomatic than b.notEmpty == false
    return !b.notEmpty;
});

// Remove
auto removed = std::remove_if(b.begin(), b.end(), predicate);

// Count
auto count = b.end() - removed;

// Erase.
b.erase(removed, b.end());

人们应该被夺走键盘,因为他们写出了这样的代码。当然,你可以使用 std::remove_if,但为什么要让你的代码变得那么丑陋和难以阅读呢? - littleadv
1
@littleadv 不要一次性阅读所有内容。标准算法是构建块,我在这里使用它们来分离职责。如果将谓词放在单独的行上,则会发生以下4件事情:决定元素是否被删除的代码片段,隔离不需要的元素的代码片段,计算已隔离元素数量的代码片段以及删除已隔离元素的代码片段。如果您确信一个人在隔离方面是正确的,那么您很快就会知道整个算法也是正确的。 - Luc Danton
2
@littleadv:这比嵌套循环和条件语句更易读。此外,我要说你关于 false == b[count].notEmpty 的建议是本主题中最丑陋的代码片段。;-] - ildjarn
@Luc Danton - 现在你已经编辑过了,不再将函数体作为参数传递 - 这是可以的。如果你同意我的观点,就不必把它当成个人攻击。 - littleadv
1
@littleadv 这是不是意味着我可以拿回我的键盘了 :) ? - Luc Danton
@Luc,你的键盘权限已正式恢复。 :p - littleadv

2

b[count].notEmpty = false 应该改为 b[count].notEmpty == false,否则 if 语句将永远为 false

更好的做法是写成 false == b[count].notEmpty 的形式,这样左边的常量不是一个 l-value,如果你犯了(非常常见的)错误,写成了 = 而不是 ==,就会出现编译错误。


将常量放在左边是可行的,但我使用过的大多数编译器都会在条件语句中执行赋值操作时发出警告。 - Praetorian
@Praetorian - 他们可能会,但警告并不会停止编译,并且很容易被忽略... 我不会(也不会)依赖它。 - littleadv
2
如果你设置编译器将警告视为错误,它们会停止编译。你应该这样做! - Peter Alexander
1
如果你“经常”犯这个错误,那么它将被忽略掉一半的时间(因为你并不总是与一个常量进行比较)。唯一可靠的选择是学会正确使用==。然后,你可以将false放在右侧,这样更符合直觉,而且不那么让人讨厌。 ;) - jalf
我并不是在暗示你不知道区别。我是说,经过一些练习,停止犯那个错误是有可能的。这也是唯一可靠的防范方法。特别地,仅依赖于“常量在左边”的技巧是不可靠的,因为它只能保护你免受易于检测的情况的影响。初学者经常会打成a =而不是==,但随着经验的积累,区别变得如此直观,以至于你可以毫不费力地打出正确的代码。然后你就无需再依赖“常量在右边”的规则了。 - jalf
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接