如何解决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 举报,一经查实,本站将立刻删除。