CRTP复制方法警告潜在的内存泄漏

时间:2016-12-11 14:07:51

标签: c++ c++14 crtp clang-static-analyzer

我有一个对象层次结构,需要能够从基类中克隆对象。我已经遵循典型的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显示了这一点:

Clang potential memory leak

这里有内存泄漏吗?如果没有,导致误报的是什么,我该如何解决? (我不想关闭静态分析)

2 个答案:

答案 0 :(得分:1)

我找到了一种解决方法,使分析仪满意,同时仍允许使用此模式。只需撤消copyinternal_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;
};