【问题标题】:C++ Deleting an object in a vectorC ++删除向量中的对象
【发布时间】:2017-03-27 01:43:38
【问题描述】:

我目前正在使用向量来将人员保存在程序中。我正在尝试删除它

vectorname.erase(index);

我在函数中传递向量,以及我想要删除的元素。我的主要问题是如何在编译速度方面提高我的代码?

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class person {
    private:
        string name;
    public:
        person() {}
        person(string n):name(n){}
        const string GetName() {return name;}
        void SetName(string a) { name = a; }
};

void DeleteFromVector(vector<person>& listOfPeople,person target) {
    for (vector<person>::iterator it = listOfPeople.begin();it != listOfPeople.end();++it) {//Error 2-4
        if (it->GetName() == target.GetName()) {
            listOfPeople.erase(it);
            break;
        }
    }
}

int main(){
    //first group of people
    person player("Player"), assistant("Assistant"), janitor("Janitor"), old_professor("Old Professor");

    //init of vector
    vector<person> listOfPeople = { player, assistant, janitor, old_professor };

    DeleteFromVector(listOfPeople, janitor);
}

【问题讨论】:

  • 为什么你在for中定义了迭代器,却不使用它?
  • 你做错了。您正在使用 erase 但没有将其返回值作为新的迭代器,因此之后您将使用无效、损坏的迭代器。而且,还有一个更好的方法,你可以在这里看到 en.cppreference.com/w/cpp/algorithm/removeen.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
  • 好的,我在使用 erase 后立即看到了您的 break,所以我猜您毕竟没有使用无效的迭代器。
  • 不用那些东西,只需使用find_if 来查找管理员并使用它的返回值进行擦除。 Example.
  • 你为什么同时使用itindex。迭代器的全部意义在于使用它而不是索引。选择其中之一,但不能同时选择两者。

标签: c++ vector visual-studio-2015 erase


【解决方案1】:

无需定义index,可以使用迭代器访问vector中的对象:

for (vector<person>::iterator it = listOfPeople.begin(); it != listOfPeople.end(); ++it) {//Error 2-4
    if (it->GetName() == target.GetName()) {
        listOfPeople.erase(it);
        break;
    }
}

由于下一行是break for循环,这里不考虑无效迭代器问题。

【讨论】:

  • 下一行是break for循环,是否还需要考虑无效迭代器的问题?
  • 啊,这样就可以避免问题了。
  • @MartinZhai 谢谢你的信息:)
【解决方案2】:

你不需要那个循环来从向量中删除对象。只需使用std::find_if

#include <algorithm>
//...
void DeleteFromVector(vector<person>& listOfPeople, const person& target) 
{
    // find the element
    auto iter = std::find_if(listOfPeople.begin(), listOfPeople.end(),
                             [&](const person& p){return p.GetName() == target.GetName();});

    // if found, erase it
    if ( iter != listOfPeople.end())
       listOfPeople.erase(iter);
}

【讨论】:

  • 这个比公认的答案更好 - 使用 std::find_if 而不是自己做这项工作。如果为 person 类定义了 operator == 你可以使用 std::find()
  • @PaulMcKenzie,返回行中的“p”对象和“目标”导致错误。错误(活动)对象具有与成员函数“person::GetName”不兼容的类型限定符 错误(活动)对象具有与成员函数“person::GetName”不兼容的类型限定符 Error C2662 'std ::string person::GetName(void)': 无法将 'this' 指针从 'const person' 转换为 'person &'
  • @CraftedGaming 然后删除 const 或将 GetName() 设为 const 函数。最好将其设为const 函数。
  • @PaulMcKenzie 我将函数更改为 const 但它仍然包含相同的错误集
  • @CraftedGaming -- 编译时没有错误here
【解决方案3】:
listOfPeople.erase(
                   remove(listOfPeople(), listOfPeople.end(), target),
                   listOfPeople.end()
                  )

在这个擦除-删除习语中的“remove”操作会将除目标之外的所有元素移动到向量范围的前面,“erase”操作将删除末尾满足目标条件的所有元素。即使它不像迭代版本那样富有表现力,这也非常有效。

【讨论】:

  • 希望它能解决问题,但请添加对代码的解释,以便用户完全理解他/她真正想要的。
  • 见“Explaining entirely code-based answers”。虽然这在技术上可能是正确的,但它并没有解释为什么它可以解决问题或应该是选择的答案。除了帮助解决问题,我们还应该进行教育。
  • 谢谢两位。答案现在更新了解释。
猜你喜欢
  • 1970-01-01
  • 2015-02-03
  • 2011-06-10
  • 2023-03-26
  • 1970-01-01
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多