Clang++ генерирует исполняемый файл, который утечки памяти, о std:: function и лямбда
Clang++ 3.2 на ArchLinux (i686) используется для создания следующих кодов С++ 11
#include <iostream>
#include <functional>
typedef std::function<void ()> Action;
typedef std::function<int ()> Generator;
Action act(Generator const& gen)
{
return [=]()
{
std::cout << gen() << std::endl;
};
}
int main()
{
static Generator const gen([]() { return 0; });
act(gen);
return 0;
}
С clang++ test.cpp -std=c++0x && valgrind --leak-check=full --log-file=tmp.log.memcheck ./a.out
, тогда я получаю
==600== HEAP SUMMARY:
==600== in use at exit: 1 bytes in 1 blocks
==600== total heap usage: 3 allocs, 2 frees, 18 bytes allocated
==600==
==600== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==600== at 0x402B124: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==600== by 0x8048D4F: std::_Function_base::_Base_manager<main::$_1>::_M_clone(std::_Any_data&, std::_Any_data const&, std::integral_constant<bool, false>) (in /home/neuront/a.out)
==600== by 0x8048C21: std::_Function_base::_Base_manager<main::$_1>::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation) (in /home/neuront/a.out)
==600== by 0x8049455: std::function<int ()>::function(std::function<int ()> const&) (in /home/neuront/a.out)
==600== by 0x8049283: std::function<int ()>::function(std::function<int ()> const&) (in /home/neuront/a.out)
==600== by 0x80489B1: act(std::function<int ()> const&) (in /home/neuront/a.out)
==600== by 0x8048A6C: main (in /home/neuront/a.out)
==600==
==600== LEAK SUMMARY:
==600== definitely lost: 1 bytes in 1 blocks
==600== indirectly lost: 0 bytes in 0 blocks
==600== possibly lost: 0 bytes in 0 blocks
==600== still reachable: 0 bytes in 0 blocks
==600== suppressed: 0 bytes in 0 blocks
==600==
==600== For counts of detected and suppressed errors, rerun with: -v
==600== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Я не уверен, есть ли какие-либо проблемы с этим кодом (и вызывает только одну байтовую утечку), но утечки памяти не будет, если вы используете g++ 4.7 для компиляции. Любое предложение об этом?
Ответы
Ответ 1
Распределение происходит здесь:
return [=]()
Что говорит "Захват всего, что не является параметром по стоимости", включая "std:: cout" и т.д., что означает создание их копий.
Следующий код передает ту же проверку компиляции и valgrind без ошибок, но с оговоркой, что программист отвечает за обеспечение того, чтобы время жизни параметра "gen" больше, чем время жизни лямбда.
#include <iostream>
#include <functional>
typedef std::function<void ()> Action;
typedef std::function<int ()> Generator;
Action act(Generator const& gen)
{
return [&gen]()
{
std::cout << gen() << std::endl;
};
}
int main()
{
static Generator const gen([]() { return 0; });
act(gen);
return 0;
}
См. также http://en.cppreference.com/w/cpp/language/lambda
Ответ 2
Статические переменные, как известно, "вызывают" эти утечки памяти в valgrind для сложных объектов, которые дополнительно выделяют что-то в куче (например, например, контейнеры STL и т.д.).
На практике не о чем беспокоиться, но, конечно, это разрушает "мою программу, свободную от утечек", и делает реальные утечки труднее обнаружить.
Я бы предположил, что g++ просто поддерживает генератор полностью в области BSS, в то время как clang видит необходимость выделения байта в куче.