clang 静态分析器使用 unique_ptr 报告内存泄漏假阳性?

问题描述

我有一个类使用 std::unique_ptr 作为内存,但 clang-check 报告“潜在的内存泄漏”。我不知道为什么,如果我做错了什么,或者这是否是误报。运行 valgrind 没有发现任何泄漏。

代码(见下文)嵌套了几层,我无法在仍然触发泄漏检查的同时进一步减少它。

本质上,我有一个Func,其行为类似于 std::function,即它是任何提供(鸭子类型)接口 double operator()(double x) const 的函子对象的类型擦除包装器.它使用 std::unique_ptr<Callable> 包装此对象,其中 Callable 是所述方法的接口(并且具有用于多态复制的虚拟析构函数和克隆)。类型擦除是使用类模板 CallableImpl 实现的,该模板具有实际的函子作为成员。 因此,Func 类型的对象具有值语义,并且由于 unique_ptr 和虚拟 dtor,应该可以以任何方式复制而不会泄漏内存。

然后我有几个辅助类来练习这个,相互包裹,以触发泄漏检查。

#include <iostream>
#include <memory>

// Interface for a functor object providing method double operator()(double)
class Callable
{
public:
    using FuncPtr = std::unique_ptr<Callable>;

    Callable() = default;
    virtual ~Callable() = default;

    // Call function
    virtual double operator()(double x) const = 0;

    // polymorphic copy constructor
    virtual FuncPtr clone() const = 0;
};

// Generic implementation that equips Functor with the Callable interface
// as long as it provides the required (non-virtual) method.
template <typename Functor>
class CallableImpl : public Callable
{
public:
    CallableImpl(Functor f) : f(std::move(f)) {}
    CallableImpl(const CallableImpl&) = default;
    CallableImpl(CallableImpl&&) = default;


    double operator()(double x) const override
    {
        return f(x);
    }

    FuncPtr clone() const override
    {
        return std::make_unique<CallableImpl>(*this);
    }

private:
    Functor f;
};

// Type-erased functor
class Func final
{
    using FuncPtr = Callable::FuncPtr;
    FuncPtr func;

public:
    // Type erasing constructor for generic callables
    template <typename T>
    Func(T callable)
        : func(std::make_unique<CallableImpl<T>>(std::move(callable)))
    {
    }

    // copy constructor
    Func(const Func& rhs) : func(rhs.func->clone()) {}
    // Move constructor
    Func(Func&&) = default;

    // copy assignment
    Func& operator=(const Func& rhs)
    {
        func = rhs.func->clone();
        return *this;
    }
    // Move assignment
    Func& operator=(Func&& rhs) = default;

    // Call function
    double operator()(double x) const
    {
        return (*func)(x);
    }
};

// A class that implements the Callable concept of Func,including some state
class AddConstant
{
public:
    AddConstant(double c) : c(c) {}
    double operator()(double  x) const { return x + c; }

private:
    double c;
};

// A class that takes a Func and trivially executes
class Foo
{
public:
    Foo(Func f) : f(std::move(f)) {}
    double operator()(double x) const { return f(x); }

private:
    Func f;
};

// Some additional wrapping that should do nothing but is needed for the
// leak warning to trigger.
struct WrapFoo
{
    Foo f;
};

// This is also needed tp trigger the warning for some reason,although directly
// using the expression herein works fine.
WrapFoo makeWrapFoo(const Func& fa)
{
    return {Foo(fa)};
}


int main()
{
    AddConstant callable = AddConstant(3);    // ok
    Func func = {AddConstant(3)};             // ok
    Foo foo = {func};                         // ok
    Foo copy = foo;                           // ok
    WrapFoo wrappedFoo = WrapFoo{Foo(func)};  // ok
    WrapFoo wrapper = makeWrapFoo(func);      // Potential leak of memory

    std::cout << "f(42): " << wrapper.f(42)
              << ",direct: " << callable(42) << std::endl;
}

clang 分析器(clang 版本 12.0.0)输出为:

$ /opt/homebrew/Cellar/llvm/12.0.0/libexec/c++-analyzer -std=c++17 main.cpp

main.cpp:124:5: warning: Potential leak of memory pointed to by field '__value_' [cplusplus.NewDeleteLeaks]
    WrapFoo wrapper = makeWrapFoo(func);      // Potential leak of memory
    ^~~~~~~~~~~~~~~
1 warning generated.

这是在 libc++ 上。在带有 libstdc++ 的 linux 机器上,我也收到警告。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)