std::unique_ptr 在循环中 - 内存泄漏

std::unique_ptr in a loop - memory leaks

本文关键字:泄漏 循环 内存 unique ptr std      更新时间:2023-10-16

unique_ptr是否按预期正确使用?代码以一些内存泄漏(可能是误报?或真正的泄漏?)结束。我认为将所有权转移到 RunSimulation,unique_ptr 的生命将结束,并且在循环中创建更新的生命周期,但是,这会导致访问冲突。

理想情况下,我希望main()中的一个unique_ptr对象在main()中过期,另一个发送到main外部以在RunSimulation()中释放。

class Result { public: int n; };
void RunSimulation(std::unique_ptr<Result> result) {result->n = 0;}
void main()
{
        boost::thread_group threads;
        std::unique_ptr<Result> r;
        std::unique_ptr<Simulation> sim = std::make_unique<Simulation>();
        for (int i = 0; i < 10; i++)
        {
            r = std::unique_ptr<Result>(new Result);
            //Erroneous lines:
            //threads.create_thread(boost::bind(&RunSimulation, std::move(r)));
            //threads.create_thread([&] {RunSimulation(std::move(r));  });
        }
        threads.join_all();
}

您没有内存泄漏,但这并不是说您的代码是正确的。看看你的循环:

for (int i = 0; i < 10; i++)
{
    r = std::unique_ptr<Result>(new Result);
    threads.create_thread([&] { RunSimulation(r.get()); });
}

每次将新的 Result 实例分配给 r 时,unique_ptr都会删除旧的实例。这可能在获取其指针的线程使用它之前发生,在这种情况下,您正在尝试取消引用已删除的内存。这是未定义的行为。

更新下面是一个示例

#include <thread>
#include <memory>
#include <iostream>
class Result
{
public:
    Result() : x(0) { }
    int x;
};

void RunSimulation(std::unique_ptr<Result> result)
{
    result->x = 10;
    std::cout << result->x << std::endl;
}

int main()
{
    std::unique_ptr<Result> result = std::make_unique<Result>();
    std::thread t(RunSimulation, std::move(result));
    t.join();
}

下面是否正确使用unique_ptr

不。

r 指向的对象在连续迭代中被取消,同时它可能仍在复制指针的线程中使用,从而导致未定义的行为。

代码以一些内存泄漏结束(可能是误报?

可能。在销毁r之前调用_CrtDumpMemoryLeaks,以便尚未解除分配内存。

我以为将所有权转移到RunSimulation,unique_ptr的生命将结束

这是一个明智的想法。我建议这样做。

但是,这最终会导致访问冲突。

然后该程序可能也有一个错误。


    for (int i = 0; i < 10; i++)
    {
        r = std::unique_ptr<Result>(new Result);
        threads.create_thread([&] { RunGridSimulation(std::move(r)); });
    }
此替代方法

的问题(好吧,原始替代方法中也存在相同的问题)是捕获对局部变量的引用,但在超出局部变量范围的线程中使用 lambda。所有线程都将指向同一个变量,如果线程没有碰巧与循环完美交错,那么一个线程将从另一个线程已经移动的唯一指针移动,从而导致指针被取消引用时出现未定义的行为。

您必须将唯一指针移动到 lambda 中,而不是通过引用捕获它。