std::function 的“潜在内存泄漏”

iva*_*ult 5 c++ clang-tidy

考虑这个例子:

#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;
}
Run Code Online (Sandbox Code Playgroud)

Demo(最右边的选项卡上有完整的消息)

当使用 clang-tidy 检查此代码时,我收到以下警告:

warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
Run Code Online (Sandbox Code Playgroud)

行号指向函数的作用域出口wrap

据我了解该消息,该工具担心结果表格callbacks::foo可能会丢失。但我不明白这怎么可能:std::function是一个安全的类,应该在其析构函数中很好地销毁所有内容。而且它的寿命是由向量控制的,这也是安全的。

这里发生了什么?我该如何解决这个问题或解决方法?

不幸的是,我不能仅仅抑制警告,因为该代码分散在代码库中的各处。

Yak*_*ont 2

尝试

closure_vec retval;
retval.reserve(sizeof...(calls)+1);
retval.push_back(callbacks::foo(number));
( retval.push_back(std::forward<calls_t>(calls)), ... );
return retval;
Run Code Online (Sandbox Code Playgroud)

这避免了 constinitializer_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))};
Run Code Online (Sandbox Code Playgroud)

问题callbacks::foo(number)出在初始化过程中。