"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 函数的副本,因此也应该更有效率。

Live example.

我在这里尝试使用 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) 初始化中。