Будет ли динамическое выделение во время цикла for создавать утечку памяти?

У меня проблема с решением проблемы динамического распределения... У меня есть функция 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)

Как я могу избежать возможной утечки памяти за счет динамического выделения переменной, но при этом иметь возможность заполнить кортеж двумя указателями?


person Syntactic Fructose    schedule 02.07.2014    source источник
comment
Используйте умный указатель, например, unique_ptr или shared_ptr.   -  person Neil Kirk    schedule 03.07.2014
comment
Любой вызов new() без соответствующего удаления вызовет утечку памяти. Используйте умные указатели, как предложил @NeilKirk.   -  person πάντα ῥεῖ    schedule 03.07.2014
comment
@NeilKirk как насчет boost::scoped_ptr<double>, это сработает? Или он будет освобожден в конце лямбда-функции   -  person Syntactic Fructose    schedule 03.07.2014


Ответы (1)


Я бы предпочел просто увидеть это как кортеж двойников (или их массив); он удаляет все догадки, созданные кортежем указателей на удвоения.

Вместо того, чтобы думать об этом как о потенциальной утечке, подумайте об этом с точки зрения права собственности. Когда вы объявляете локальную переменную типа double, она принадлежит стеку, и она будет очищена. Когда вы создаете один из типов double*, стек владеет указателем, но не владеет значением, поэтому значение не может быть очищено. Ясно, что просто объявить double проще и легче, поэтому, если есть такая возможность, предпочтите ее.

Теперь рассмотрим других потенциальных владельцев. Кортеж, содержащий типы POD, такие как std::tuple<double, double>, будет владеть и затем очищать двойники, но кортеж, содержащий тип указателя, не ясен. Очистка std::tuple<double*, double*> не очистит двойников. Очевидно, что просто использовать кортеж двойников проще и легче, поэтому, если это вариант, предпочитайте его.

Но я предполагаю, что по разным причинам вам нужно использовать кортеж указателей на удвоение.

Затем подумайте, какое время жизни вам нужно для ваших базовых данных. Как вы можете получить эту жизнь? Можете ли вы передать право собственности на двойники чему-то другому, что будет очищено в нужное время, и сохранить их адреса в указателях кортежа, не являющихся владельцами, на двойники? Например, ваша лямбда захватывает внешний контейнер по ссылке, помещает в него свои двойники и сохраняет только их адреса в кортежах.

Вот попытка показать, что я имею в виду... но будьте осторожны, делая это с вектором, как я его показываю. Я ничего не знаю о hpx::parallel::reduce, но полагаю, что его параллельная природа сделает эту упрощенную версию совершенно небезопасной. Два чередующихся вызова push_back и back приведут к созданию некорректных кортежей; два перекрывающихся вызова 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()); });
person Michael Urman    schedule 02.07.2014
comment
спасибо за ответ, и да, по разным причинам я не могу просто использовать <double,double> (хотя я бы хотел). В частности, файл является только эталоном, поэтому я хотел бы, чтобы указатели оставались в живых до конца теста (что совсем не долго). Я попытался сделать что-то похожее на ваш vector, но с atomic<double>, но С++ 11 не поддерживает оператор += для атомарных двойников, и меня застрелили. - person Syntactic Fructose; 03.07.2014
comment
@SyntacticFructose Если время жизни вашей программы ненамного превышает время жизни ваших двойников, утечка не обязательно необоснованна. (Если только это не обесценит то, что вы пытаетесь измерить с помощью теста.) Конечно, чтобы использовать результаты, вам все равно понадобится реальное решение. - person Michael Urman; 03.07.2014