2016-12-11 36 views
6

我有一个对象层次结构,需要能够从基类中克隆对象。我遵循了典型的CRTP模式,除了我也希望能够在子节点直接调用副本时返回子类。为此,我按照这里的建议:https://stackoverflow.com/a/30252692/1180785CRTP复制方法警告潜在的内存泄漏

它似乎工作正常,但叮war警告我,我有潜在的内存泄漏。我已经减少了代码到这个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 potential memory leak

是否存在内存泄漏?如果不是,导致误报的原因是什么,我该如何解决? (我宁愿不关闭静态分析)

+0

您展示[不叫'CRTP :: copy'](程序http://rextester.com/ UBB92957)。我怀疑你运行的代码可能与你展示的代码不同。 –

+0

@IgorTandetnik好点;我在减少它的时候错过了。但是,我发布的警告是直接从我发布的代码中获取的,所以它确实运行了CRTP :: copy。这让我觉得这实际上可能是与虚拟方法有关的分析器中的一个错误。 – Dave

+0

@IgorTandetnik我更新了代码,并对问题进行了改进演示,它删除了副本上不必要的“虚拟”并删除了阵列。这个确实调用了CRTP :: copy方法,并且铿锵分析是一样的。 – Dave

回答

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的情况下,因为要解决copy内CRTP时,它会更喜欢CRTP的覆盖(即使它不是一个虚拟的方法),所以没有无限循环。

至于为什么分析仪对此订单感到满意,但对原订单不满意,我不知道。

1

我认为分析仪在您的copy方法中被static_cast弄糊涂了。如果您只是将其更改为dynamic_cast,则停止将该行标记为内存泄漏。这使我相信它认为你可能将一个基类型实例(CRTP<T>)转换为其派生类型(T),这在取消引用时当然是无效的。你显然不这样做,所以这可能是泄漏检测器中的一个错误,或者它可能比我现在想的更微妙。现在可能不是错误,但是如果Impl变成更复杂的类型(例如,具有多重继承的类型),它可能会成为问题(在copy-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; 
}; 
+0

请参阅我对你的评论的回答,以解释为什么'internal_copy'在这个用例中不能返回'T *'。有趣的是'dynamic_cast'使它开心;它不是我测试过的,因为我正在使用'-no-rtti',但正如你所说;也许它只是认为static_cast可能会转换为错误的类型。 – Dave