2016-12-11 8 views
6

Nesne hiyerarşisi var ve nesneleri temel sınıftan klonlayabilmem gerekiyor. Tipik bir CRTP modelini takip ettim, ayrıca çocuk bir çocuğa doğrudan kopyalama yapıldığında çocuk sınıfını iade etmek istiyorum. Bunu yapmak için şu öneriyi takip ettim: https://stackoverflow.com/a/30252692/1180785CRTP kopyalama yöntemi, potansiyel bellek sızıntısı konusunda uyarıyor

İyi çalışıyor gibi görünüyor, ancak Clang bana potansiyel bellek sızıntısı olduğumu söyledi. Bu MCVE aşağı kodunu düşürdük:

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; 
} 
Bildiğim kadarıyla söyleyebilirim, orada hiçbir olası bellek sızıntısı, ama XCode ile çınlama çalışan bu gösterir

:

Clang potential memory leak

burada bir bellek sızıntısı var mı? Değilse, yanlış pozitife neyin neden olduğu ve bu konuda nasıl çalışabilirim? (Statik analizi devre dışı bırakmamayı tercih ederim)

+0

Eğer ([ 'cRTP :: copy' çağırmaz] göstermek programı http://rextester.com/ UBB92957) hiç. Çalıştığınız kodun gösterdiğiniz birinden farklı olabileceğinden şüpheleniyorum. –

+0

@IgorTandetnik iyi bir nokta; Onu indirirken onu özledim. Ancak, gönderdiğim uyarı doğrudan gönderdiğim koddan alınır, dolayısıyla bir şekilde gerçekten de CRTP :: copy. Bu, bunun aslında sanal yöntemlerle ilgili analizörde bir hata olabileceğini düşünmemi sağlıyor. – Dave

+0

@IgorTandetnik Koddaki gereksiz "sanal" yı kaldıran ve diziyi kaldıran, sorunun geliştirilmiş bir gösterimi ile kodu güncelledim. Bu gerçekten de CRTP :: copy yöntemini çağırır ve clang analizi aynıdır. – Dave

cevap

1

Bu modelin kullanımına izin verirken analizörü mutlu eden bir çözüm buldum. Basitçe copy ve internal_copy arasındaki bağlantıyı ters:

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)); 
    } 
}; 

cRTP içeride copy çözme zaman sanal bir yöntem olmadığı halde, bu (CRTP geçersiz kılmasını tercih edecektir, çünkü bu hala orijinal öneri here bağlamında çalışır), böylece sonsuz bir döngü yoktur.

Analizörün bu siparişten neden memnun olduğunu ancak orijinal siparişten memnun olmadığına dair hiçbir fikrim yok.

1

Analizörüntarafından copy yönteminizde karıştırıldığını düşünüyorum. Bunu dynamic_cast olarak değiştirirseniz, satırı bellek sızıntısı olarak işaretlemekten vazgeçirir. Bu, türetilmiş bir türe (CRTP<T>) türetilmiş bir türe (CRTP<T>) döküm yapılacağını düşündüğünüze inanıyor. Açıkçası bunu yapmıyorsunuz, bu yüzden sızıntı detektöründe bir hata olabilir ya da şu an düşündüğümden daha ince bir şey olabilir. Artık bir hata olmayabilir, ancak Impl daha karmaşık bir türse (örneğin, birden fazla kalıtımla), bir sorun olabilir (kopya CTOR çağrısında static_cast'unuz olacak).

(daha az maket ile) Bu uygulama benim için de sıfır sızıntıları vardı:

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

Bu kullanım vakasında 'internal_copy' niçin' T * 'döndüremediğine ilişkin bir açıklama için yaptığınız yoruma cevabımı görün. Dynamic_cast’in bunu mutlu etmesi ilginçtir; test ettiğim bir şey değil çünkü -no-rtti'yi kullanıyorum, ama dediğin gibi; Belki de sadece static_cast'in yanlış türde yazıldığını düşünüyor. – Dave