我有一个对象层次结构,需要能够从基类中克隆对象。我已经遵循典型的CRTP模式,除了我还希望能够在孩子直接调用副本时返回子类。为此,我已按照此处的建议:https://stackoverflow.com/a/30252692/1180785
它似乎工作正常,但Clang警告我,我有潜在的内存泄漏。我已将代码缩减到此MCVE:
template <typename T>
class CRTP {
protected:
virtual CRTP<T> *internal_copy(void) const {
return new T(static_cast<const T&>(*this));
}
public:
T *copy(void) const {
return static_cast<T*>(internal_copy());
}
virtual ~CRTP(void) = default;
};
class Impl : public CRTP<Impl> {
};
int main(void) {
Impl a;
Impl *b = a.copy();
delete b;
}
据我所知,那里没有可能的内存泄漏,但是通过XCode运行Clang显示了这一点:
这里有内存泄漏吗?如果没有,导致误报的是什么,我该如何解决? (我不想关闭静态分析)
答案 0 :(得分:1)
我找到了一种解决方法,使分析仪满意,同时仍允许使用此模式。只需撤消copy
和internal_copy
:
template <typename T>
class CRTP : public Base {
protected:
virtual CRTP<T> *internal_copy(void) const {
return copy();
}
public:
T *copy(void) const {
return new T(static_cast<const T&>(*this));
}
};
这仍然适用于原始建议here的上下文,因为在CRTP中解析copy
时,它会更喜欢CRTP的覆盖(即使它不是虚拟方法) ),所以没有无限循环。
至于为什么分析仪对此订单感到满意但对原始订单不满意,我不知道。
答案 1 :(得分:1)
我认为分析器对static_cast
方法中的copy
感到困惑。如果您只是将其更改为dynamic_cast
,则会停止将该行标记为内存泄漏。这使我相信它认为您可能将基类型实例(CRTP<T>
)转换为其派生类型(T
),当取消引用时它当然会无效。你显然没有这样做,所以这可能是泄漏探测器中的一个错误,或者它可能比我现在想的更微妙。它现在可能不是错误,但是如果Impl
变成更复杂的类型(例如,具有多重继承的类型),它可能会成为一个问题(复制CTOR调用中的static_cast
也是如此)
这个实现(使用更少的演员表)也没有泄漏:
template <typename T>
class CRTP {
protected:
virtual T *internal_copy() const {
return new T(static_cast<const T&>(*this));
}
public:
T *copy() const {
return internal_copy();
}
virtual ~CRTP() = default;
};