首页 > 解决方案 > 在向量中使用擦除时双重释放或损坏(fasttop)。知道它们的索引,你怎么能擦除向量的几个项目?

问题描述

我正在从事一个“大”项目,但遇到了一个分段错误,我最终将其缩小为一个更简单且可重现的示例:

我要放两段代码。第一的:

#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{

    std::vector<int> someVector;

    printf("1\n");
    someVector.push_back(1);

    printf("2\n");
    someVector.push_back(2);

    printf("3\n");
    someVector.push_back(3);


    someVector.erase(someVector.begin());
    someVector.erase(someVector.begin());

    return 0;
}

在这里,一切正常。行。现在让我们尝试一些更复杂的东西。让我们使用我自己定义的类的向量,而不是使用整数向量。

注意:我不是专家,我可能在定义类时犯了错误。之所以在类定义中有一个拷贝构造函数,是因为参数变量,实际上是一个指向另一个类的指针(而不是一个int),我在真实例子的构造函数体上拷贝了它。

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

class ActionType {
  public:
    std::string name;
    int type;
    int * parameters;

    ActionType(const std::string _name, const int _type
        );

    ActionType(const ActionType &);   

    ~ActionType(){
        // Direct implementation of destructor
        printf("DELETING\n");
        delete parameters;
    }

  };

 // Implementation of initializer      
 ActionType::ActionType(const std::string _name, const int _type)
        : name(_name)
        , type(_type)
        , parameters(new int(5))
{
}

 // Implementation of copy constructor
 ActionType::ActionType(const ActionType & actionType)
     : name(actionType.name)
      , type(actionType.type)
      , parameters(new int(*actionType.parameters))

{
    printf("COPYING\n");
}

int main()
{
    ActionType actionType("foo", 1);

    std::vector<ActionType> actions;

    printf("1\n");
    actions.push_back(actionType);

    printf("2\n");
    actions.push_back(actionType);

    printf("3\n");
    actions.push_back(actionType);

    actions.erase(actions.begin());
    actions.erase(actions.begin());

    return 0;
}

这应该几乎相同,但会引发错误:

*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001618c70 ***                             
Aborted (core dumped)

问题是,在我的真实示例中,我需要一种方法来删除向量的几个项目,为此我有类似的东西:

for (int i (...)){
    int indexToDelete = getIndex();
    vector.erase(vector.begin()+indexToDelete);
}

我也可以使用类似的东西:

std::vector<int> indexes;
for (int i (...)){
    int indexToDelete = getIndex();
    indexes.push_back(indexToDelete);
}
vector.erase(indexes);

但我还没有想到任何功能可以做到这一点。我已经看到其他答案,他们使用 sort 将所有项目放在最后以及在他们调用 pop_back 之后删除,但它似乎不是超级干净。

无论如何,总而言之

标签: c++classvectorerase

解决方案


您缺少班级的赋值运算符。这std::vector要求您的类具有正确的复制语义,而您的类ActionType没有正确的复制语义。

为您编写的类添加赋值运算符很简单:

#include <algorithm>
//...
class ActionType
{
   //...
   ActionType& operator=(const ActionType &);
   //...
};

ActionType& ActionType::operator=(const ActionType &rhs)
{
    if ( this != &rhs )
    {
        ActionType temp(rhs);
        std::swap(temp.name, name);
        std::swap(temp.type, type);
        std::swap(temp.parameters, parameters);
    }  // <-- The temp is destroyed here, along with the contents.
    return *this;
}

上面使用了复制/交换习语来实现赋值运算符。

请注意,当添加赋值运算符时,代码现在可以工作。

编辑:

赋值运算符的另一种形式可以是:

class ActionType
{
   //...
   ActionType& operator=(ActionType);
   //...
};

ActionType& ActionType::operator=(ActionType temp)
{
    std::swap(temp.name, name);
    std::swap(temp.type, type);
    std::swap(temp.parameters, parameters);
    return *this;
}

推荐阅读