在运行时添加和删除列表

时间:2013-07-20 18:45:10

标签: c++ list debugging stl

我有一个模拟程序。在模拟的主要类中,我是“创建+添加”和“删除+销毁”代理。

问题在于偶尔(每运行3-4次一次)程序崩溃,因为我显然在主循环中调用了无效代理的功能。该程序大部分时间都可以正常工作。列表中通常有数千个代理。

  • 我不知道我的循环中是否有可能存在无效的代理。
  • 调试代码非常困难,因为我在“Agent :: Step函数”中收到内存异常(为时已晚,因为我无法理解列表中的无效代理是如何被调用的) 。

    当我查看Agent :: Step函数(异常点)中的Agent引用时,代理中的数据没有意义,甚至没有初始化的数据。所以它绝对无效。

    void World::step()
    {
        AddDemand();
    
        // run over all the agents and check whether they have remaining actions
        // Call their step function if they have, otherwise remove them from space and memory
        list<Agent*>::iterator it = agents_.begin();
        while (it != agents_.end())
        {
            if (!(*it)->AllIntentionsFinished())
            {
                (*it)->step();
                it++;
            }
            else
            {
                (*it)->removeYourselfFromSpace();  //removes its reference from the space
                delete (*it);
                agents_.erase(it++);
            }
        }
    }
    
    void World::AddDemand()
    {
        int demand = demandIdentifier_.getDemandLevel(stepCounter_);
        for (int i = 0; i < demand; i++)
        {
            Agent*  tmp  = new Agent(*this);
            agents_.push_back(tmp);
        }
    }
    
    Agent:
    
    bool Agent::AllIntentionsFinished()
    {
        return this->allIntentionsFinished_;  //bool flag will be true if all work is done
    }
    

1- VStudio 2012优化循环(如果可能,在多线程中运行)是否可能产生问题?

2-有关调试代码的任何建议吗?

2 个答案:

答案 0 :(得分:2)

如果您正在运行多线程代码,那么您需要添加代码来保护诸如向列表中添加项目和从列表中删除项目之类的内容。您可以创建一个包装器,可以非常轻松地为容器添加线程安全性 - 在您对底层容器执行可能的修改操作时,可以锁定一个互斥锁。

template <class Container>
thread_safe {
    Container c;
    std::mutex m;
public:
    void push_back(typename Container::value_type const &t) { 
         std::lock_guard l(m);
         c.push_back(t);
    }
    // ...
};

其他几点:

  1. 您几乎可以肯定通过直接保持Agent列表来清理您的代码,而不是指向您必须动态分配的代理的指针。

  2. 您的Agent::RemoveYourselfFromSpace看起来/听起来很像应该由Agent的析构函数处理的内容。

  3. 通过使用一些标准算法,您几乎肯定可以做更多的事情来清理代码。

  4. 例如,我认为你的step可能是这样写的:

    agents.remove_if([](Agent const &a) { return a.AllIntentionsFinished(); });
    
    std::for_each(agents.begin(), agents.end(),
                  [](Agent &a) { a.step(); });
    

    ...或者,您可能更喜欢继续使用显式循环,但使用类似:

    for (Agent & a : agents)
        a.step();
    

答案 1 :(得分:0)

问题在于:

agents_.erase(it++);

请参阅Add and remove from a list in runtime

我在您显示的代码中没有看到任何线程安全的组件,因此如果您运行多个线程并在它们之间共享数据,那么绝对可能会遇到线程问题。例如,你这样做:

(*it)->removeYourselfFromSpace();  //removes its reference from the space
delete (*it);
agents_.erase(it++);

这是解锁列表的最差订单。你应该:从列表中删除,破坏对象,删除对象,按顺序。

但是如果你没有专门创建共享列表/代理的线程,那么线程可能不是你的问题。