"Potential memory leak" 和 std::function
"Potential memory leak" with std::function
考虑这个例子:
#include <vector>
#include <string>
#include <functional>
#include <iostream>
using closure_type = std::function<void(void)>;
using closure_vec = std::vector<closure_type>;
class callbacks {
static closure_type common(std::string name, uint32_t number) {
return [number, name]() { std::cout << name << number << std::endl; };
}
public:
static closure_type foo(uint32_t number) { return common("foo ", number); }
static closure_type print(std::string msg) {
return [msg]() { std::cout << "print " << msg << std::endl; };
}
};
template <typename... calls_t> closure_vec wrap(uint32_t number, calls_t &&... calls) {
return closure_vec {
callbacks::foo(number),
std::forward<calls_t>(calls)...,
};
}
int main() {
auto vec = wrap(42,
callbacks::print("hello, "),
callbacks::print("world"));
for(auto &e: vec)
e();
return 0;
}
Demo(在最右边的选项卡上有一条完整的消息)
当使用 clang-tidy 检查此代码时,我收到以下警告:
warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
行号指向 wrap
函数的作用域出口。
据我了解该消息,该工具担心 callbacks::foo
的结果可能会丢失。但我不明白这怎么可能:std::function
是一个安全的 class 并且应该在其析构函数中很好地销毁所有内容。它的生命周期也由向量控制,这也是安全的。
这是怎么回事?我该如何解决这个问题或解决方法?
不幸的是,我不能只抑制警告,因为这段代码散布在代码库中的各个地方。
尝试
closure_vec retval;
retval.reserve(sizeof...(calls)+1);
retval.push_back(callbacks::foo(number));
( retval.push_back(std::forward<calls_t>(calls)), ... );
return retval;
这避免了 const initializer_list 包含您的代码创建的 std 函数的副本,因此也应该更有效率。
我在这里尝试使用 C 样式数组,但尽管没有使用 std::initializer_list.
,我也收到了警告
这也有效:
std::array<closure_type, sizeof...(calls)+1> tmp ={
nullptr,
std::forward<calls_t>(calls)...
};
tmp[0] = callbacks::foo(number);
return {std::make_move_iterator(std::begin(tmp)), std::make_move_iterator(std::end(tmp))};
问题出在 callbacks::foo(number)
初始化中。
考虑这个例子:
#include <vector>
#include <string>
#include <functional>
#include <iostream>
using closure_type = std::function<void(void)>;
using closure_vec = std::vector<closure_type>;
class callbacks {
static closure_type common(std::string name, uint32_t number) {
return [number, name]() { std::cout << name << number << std::endl; };
}
public:
static closure_type foo(uint32_t number) { return common("foo ", number); }
static closure_type print(std::string msg) {
return [msg]() { std::cout << "print " << msg << std::endl; };
}
};
template <typename... calls_t> closure_vec wrap(uint32_t number, calls_t &&... calls) {
return closure_vec {
callbacks::foo(number),
std::forward<calls_t>(calls)...,
};
}
int main() {
auto vec = wrap(42,
callbacks::print("hello, "),
callbacks::print("world"));
for(auto &e: vec)
e();
return 0;
}
Demo(在最右边的选项卡上有一条完整的消息)
当使用 clang-tidy 检查此代码时,我收到以下警告:
warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
行号指向 wrap
函数的作用域出口。
据我了解该消息,该工具担心 callbacks::foo
的结果可能会丢失。但我不明白这怎么可能:std::function
是一个安全的 class 并且应该在其析构函数中很好地销毁所有内容。它的生命周期也由向量控制,这也是安全的。
这是怎么回事?我该如何解决这个问题或解决方法?
不幸的是,我不能只抑制警告,因为这段代码散布在代码库中的各个地方。
尝试
closure_vec retval;
retval.reserve(sizeof...(calls)+1);
retval.push_back(callbacks::foo(number));
( retval.push_back(std::forward<calls_t>(calls)), ... );
return retval;
这避免了 const initializer_list 包含您的代码创建的 std 函数的副本,因此也应该更有效率。
我在这里尝试使用 C 样式数组,但尽管没有使用 std::initializer_list.
,我也收到了警告这也有效:
std::array<closure_type, sizeof...(calls)+1> tmp ={
nullptr,
std::forward<calls_t>(calls)...
};
tmp[0] = callbacks::foo(number);
return {std::make_move_iterator(std::begin(tmp)), std::make_move_iterator(std::end(tmp))};
问题出在 callbacks::foo(number)
初始化中。