谁能解释一下为什么此c++代码崩溃(实际上它不会崩溃,而是valgrind抱怨无效的内存访问)。

这个想法很简单。 Controller 会创建一些 worker 。每个工作人员都会得到函子对象,一旦完成工作,该对象将擦除该工作人员。谁能提出一些解决方案?

typedef boost::function<void()> Callback;

struct Worker
{
    void start(Callback onFinnish)
    {
        // Called when finnished working
        onFinnish();
    }
};

typedef boost::shared_ptr<Worker> WorkerPtr;

struct Controler
{
    void start()
    {
        for(int i = 0; i < 5; ++i)
        {
            auto workerPtr = boost::make_shared<Worker>();
            workers.insert(workerPtr);
        }

        for(const auto &workerPtr: workers)
        {
            workerPtr->start(
                [this, workerPtr] ()
                {
                    workers.erase(workerPtr);
                    if(workers.size() == 0)
                    {
                        std::cout << "All workers done!" << std::endl;
                    }
                }
            );
        }
    }

    std::set<WorkerPtr> workers;
};

// Somewhere in code
Controler c; c.start();

在评论后编辑:
我实现了这样的for auto循环,现在可以工作了:
    for(auto workerIt = workers.begin(); workerIt != workers.end();)
    {
        auto nextWorker = workerIt; ++nextWorker;

        (*workerIt)->start(
            [this, workerIt] ()
            {
                workers.erase(workerIt);
                if(workers.empty())
                {
                    onWorkersDone();
                }
            }
        );

        workerIt = nextWorker;
    }

最佳答案

在您的for范围内,您可以修改涉及UB的循环内的容器。

创建集合的副本应解决您的问题:

for(const auto &workerPtr: std::set<WorkerPtr>(workers)) // create a copy of the set
{
    workerPtr->start(
        [this, workerPtr] ()
        {
            workers.erase(workerPtr);
            if(workers.size() == 0)
            {
                std::cout << "All workers done!" << std::endl;
            }
        }
    );
}

编辑:
正如DietmarKühl所述,如果您的方法start启动一个新线程,那么您将在set上进行数据竞争。

10-08 11:25