【问题标题】:c++ when creating new object: iterator not incrementablec++ 创建新对象时:迭代器不可递增
【发布时间】:2014-05-27 20:30:06
【问题描述】:

我正在处理一项任务,即创建一群兔子,它们可以在每一轮中繁殖。所以我定义了一个Bunny的类(个体),然后定义了一个Troop的类,向量指向不同的兔子。 我的问题是,每次使用new循环创建对象Bunny,都会报错:

“调试断言失败!!...向量迭代器不可递增...”

这是我的代码示例:

class Bunny {
private:
    string sex;
    string color;
    string name;
    int age;
public:
    string getname() { return name;};
    Bunny(); // constructor
};

class Troop {
private:
    vector<Bunny *> bunpointer;
    vector<Bunny *>::iterator it;
public:
    void newbunny();
    void multiply();
};

void Troop::newbunny() {
    Bunny * bun;  // pointer to the Bunny class
    bun = new Bunny;
    cout << "Bunny " << bun->getname() << " is born! \n";
    bunpointer.push_back(bun);
}

void Troop::multiply() {
    it = bunpointer.begin();
    while(it!=bunpointer.end()) {
        cout << (*it)->getname() << " gave a birth. ";
        newbunny();
        ++it;
    }
    it = bunpointer.begin();
}

所以如果我一开始创建 5 个兔子,并调用函数Troop::multiply,应该有 10 个兔子。一个有趣的观察是,这个错误会在 2 只兔子出生后发生。

我认为问题可能在于使用new 在迭代器循环中创建新对象。 new 可能会以某种方式中断迭代器指针 *it。但是我不确定是不是这样,如果真的是这样,该如何处理。

修改:所以实际上是使用push_back()的问题,这可能会使iterator失效!!

提前谢谢你!!

【问题讨论】:

  • 为什么你需要在这个程序中使用new?为什么不只是一个vector&lt;Bunny&gt;
  • psuh_back 使迭代器无效。
  • 嗨@chris 是的,我认为这是push_back 问题。还有@PaulMcKenzie,老实说,我真的不知道,因为我仍在努力学习C++,而我所做的只是模仿人们的程序......你能帮忙解释一下两者之间的区别吗?就我而言,我的Troop 需要不断增加。
  • @CSLearner - 请参阅我的答案,以调整您在 push_back 中看到的问题的代码和其他 cmets。

标签: c++ memory vector


【解决方案1】:

您似乎正在尝试在迭代 std::vector 时对其进行修改。由于各种原因,这通常不是一个好主意。

特别是,当您在迭代器的循环中调用newbunny() 时,您曾经持有的迭代器可能会失效,因为向量可能会在push_back 期间调整大小。

详情请见this question

【讨论】:

  • 谢谢!!我认为这是push_back 的问题。你能提出任何解决方案吗?使用vector::reserve() 可能不会起作用,因为我的Troop 会不断增加,并且所需的部队规模将是未知的。
  • @CSLearner,我认为其他答案相当清楚如何解决它。 :)
【解决方案2】:

正如其他人所说,push_back() 是你的罪魁祸首,而不是 new

缓解的一种方法是:

size_t const max(bunpointer.size());
for(size_t i(0); i < max; ++i)
{
    cout << bunpointer[i]->getname() << " gave a birth. ";
    newbunny();
}

这很有效,因为您只是在现有向量的末尾添加新兔子。循环不会考虑这些新兔子(最大值不会改变,因为您调用 newbunny()...),[i] 访问会使用当前状态的向量。

如果您要删除项目,该循环将不起作用...

附带说明:“bunpointer”这个名字不是很清楚......它不是指针,它是指针向量。

【讨论】:

  • 是的,我认为这行得通!谢谢!!不幸的是,我将来需要删除一些项目,因为兔子在程序中变老时需要死去......但我认为你使用[i]而不是iterator的方式非常聪明,我会使用在我处理delete 问题之前!
  • @CSLearner - 当您有机会进行删除时,不要使用循环来进行删除。学习 vector::erase()/remove_if() 习语。如果您不以这种方式删除,我可以向您保证,您将在 SO 上发布另一个问题,说明您的程序为什么会崩溃:)
【解决方案3】:

1) 除非您有理由这样做,否则您的代码根本不需要使用 new。代码变得更容易,并且没有内存泄漏的机会。此外,我认为不需要在 Troop 类中使用迭代器成员,除非您能证明这样做的理由。

2)至于您的直接问题,只需使用不依赖迭代器的循环即可。换句话说,一个简单的循环,从 0 到当前兔子的数量,减去 1。

这是一个例子:

#include <vector>
//...
class Troop {
   private:
       std::vector<Bunny> bunpointer;
   public:
       void newbunny();
       void multiply();
};

void Troop::newbunny() {
   bunpointer.push_back(Bunny());
}

void Troop::multiply() {
    size_t siz = bunpoiner.size(); 
    for (size_t i = 0; i < siz; ++i ) {  
       newbunny();
       cout << (*it)->getname() << " gave a birth. ";
    }
}

newbunny() 函数只是使用默认构造函数创建一个 Bunny() 并将该项添加到向量中。

如果您想使用在插入项目时不会使迭代器失效的容器,那么您可以使用 std::list 而不是 std::vector

【讨论】:

  • 谢谢先生!这真的很有帮助。我会接受你关于使用vector::erase() 的建议:)
猜你喜欢
  • 2011-09-04
  • 1970-01-01
  • 2020-02-12
  • 1970-01-01
  • 2010-09-16
  • 2013-03-23
  • 1970-01-01
相关资源
最近更新 更多