for 循环期间的动态分配会造成内存泄漏吗?

Posted

技术标签:

【中文标题】for 循环期间的动态分配会造成内存泄漏吗?【英文标题】:Will dynamic allocation during a for loop create a memory leak? 【发布时间】:2014-07-02 20:21:20 【问题描述】:

我在解决动态分配问题时遇到了问题...我有一个函数 reduce 可以累积值,在这种情况下,我正在迭代 boost::tuple<double*,double*> 的函数。我的问题在这里:

//executes this code in chunks, asynchronously
boost::tuple<double*,double*> res = hpx::parallel::reduce(hpx::parallel::par,
    iter, iter+4,                                                         
    boost::make_tuple<double*,double*>(g,h), [](reference a, reference b)  
        double *res= new double;  //dynamic allocation! I don't have anyway to delete this memory afterwards
        *res = *boost::get<1>(b) * *boost::get<0>(b);
        return boost::make_tuple<double*,double*>(res,res); );

函数参数是

template< typename ExPolicy, typename Iter, typename T, typename Func>
T reduce(ExPolicy execution_policy, Iter being, Iter end, T && start, Func && op)

如何通过动态分配变量来避免可能造成内存泄漏,但仍然能够用两个指针填充一个元组?

【问题讨论】:

使用智能指针,例如 unique_ptr 或 shared_ptr 任何没有相应删除的new() 调用都会导致内存泄漏。按照@NeilKirk 的建议使用智能指针。 @NeilKirk boost::scoped_ptr&lt;double&gt; 怎么样,可以吗?还是会在 lambda 函数结束时解除分配 【参考方案1】:

我更愿意将其视为双精度元组(或其数组);它消除了双精度指针元组创建的所有猜测。

不要将其视为潜在的泄漏,而应从所有权的角度来考虑。当你声明一个double 类型的局部变量时,堆栈拥有它,它将被清理。当您创建double* 类型之一时,堆栈拥有指针但不拥有值,因此可能不会清理该值。显然,仅声明 double 更简单、更容易,所以当这是一个选项时,更喜欢它。

现在考虑其他潜在所有者。包含 POD 类型(例如 std::tuple&lt;double, double&gt;)的元组将拥有并清理双精度,但包含指针类型的元组并不清楚。清理std::tuple&lt;double*, double*&gt; 不会清理双打。显然,仅使用双精度元组更简单、更容易,因此如果可以选择,请更喜欢它。

但是,由于各种原因,我假设您必须使用指向双精度的指针元组。

然后考虑您的基础数据需要多长的生命周期。这辈子怎么得?您能否将双精度对象的所有权授予将在正确时间清理的其他内容,并将它们的地址存储在元组的指向双精度对象的非拥有指针中?例如,让您的 lambda 通过引用捕获一个外部容器,并将您的双精度数据放入其中,并将它们的地址仅存储在元组中。

这里试图说明我的意思......但是在我展示它时要小心使用矢量。我对hpx::parallel::reduce 一无所知,但我认为它的并行性质会使这个简化版本完全不安全。对push_backback 的两次交错调用将导致创建不正确的元组;对push_back 的两次重叠调用很容易损坏向量。更复杂的版本可以同步其对容器的使用。

std::vector<double> v; // XXX: probably unsafe for parallel reduce

boost::tuple<double*,double*> res = hpx::parallel::reduce(hpx::parallel::par,
    iter, iter+4,                                                         
    boost::make_tuple<double*,double*>(g,h), [&v](reference a, reference b)  
        v.push_back(*boost::get<1>(b) * *boost::get<0>(b));
        return boost::make_tuple<double*,double*>(&v.back(), &v.back()); );

【讨论】:

感谢您的回复,是的,由于各种原因,我不能只使用&lt;double,double&gt;(尽管我希望我可以使用)。该文件具体只是一个基准,所以我想让指针保持活动状态直到测试结束(一点也不长)。我试图做一些类似于你的vector 但使用atomic&lt;double&gt;,但c++11 不支持+= 原子双精度运算符,我被击退了。 @SyntacticFructose 如果你的程序的生命周期没有明显超过你的双打的生命周期,那么泄漏不一定是不合理的。 (除非这会使您尝试使用基准测量的内容无效。)当然,要使用结果,您仍然需要一个真正的解决方案。

以上是关于for 循环期间的动态分配会造成内存泄漏吗?的主要内容,如果未能解决你的问题,请参考以下文章

动态分配泄漏内存?

闭包为什么会造成内存泄漏?

闭包为什么会造成内存泄漏?

闭包为什么会造成内存泄漏?

它是C中的内存泄漏吗?

如何在执行C ++期间动态查看堆