2015-12-15 15 views
8

Aşağıdaki adres kodu örnek:Neden QSharedPointer <T> :: tamamlanmamış nesnenin arama yıkıcısını oluşturur?

A destr 
catch! 

Ama std::make_shared ile uncomment takdirde, çıkış aşağıdaki gibidir::

#include <QCoreApplication> 
#include <QSharedPointer> 
#include <QDebug> 

#include <memory> 

class A 
{ 
public: 
    A() 
    { 
     throw 1; 
    } 
    ~A() { qDebug() << "A destr"; } 
}; 

int main(int argc, char* argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    try 
    { 
     //auto m1 = std::make_shared<A>(); 
     auto m2 = QSharedPointer<A>::create(); 
    } 
    catch (...) 
    { 
     qDebug() << "catch!"; 
    } 

    return a.exec(); 
} 

yukarıdaki kod verilir

catch! 

Peki neden eksik nesne QSharedPointer::create çağrı yok edicisi? Bu bir hata mı yoksa bir şey mi eksik?

I (kaynaklardan inşa edilmiş) MSVC2013 + Qt 5.5.1 ve MSVC2015 + Qt 5.6 ile çalıştı. Sonuç aynı.

+0

Referans için, QSharedPointer :: create() 'özel sürümünüzün kaynak kodu buradadır: http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/ qsharedpointer_impl.h? h = v5.5.1 # n420 - QT_SHAREDPOINTER_TRACK_POINTERS tanımlı olmadan oluşturduğunuzu mu sanıyorum? –

+0

Ve burada beş yıl önce yapılmış bir olasılıkla ilişkili bir Qt hatası (şu ana kadar etkinlik yok): https://bugreports.qt.io/browse/QTBUG-14637 –

+0

@JohnZwinck Evet, tanımlanmamış. Anladığım kadarıyla bu bayrak, aynı nesneye sahip olan çoklu akıllı göstericilerin hatalarını ayıklamak için kullanılır. Ya da yine de denemeliyim? – Yrchgrchh

cevap

5

Qt içinde bir hata bulduğunuz görünüyor. Sana bir hata raporu ve referansı bu şekilde alakalıdır hata bildiriminde önermek: -:

static inline QSharedPointer create() 
{ 
    typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private; 
    typename Private::DestroyerFn destroy = &Private::deleter; 

    QSharedPointer result(Qt::Uninitialized); 
    result.d = Private::create(&result.value, destroy); 

    new (result.data()) T(); 
    result.d->setQObjectShared(result.value, true); 
    result.enableSharedFromThis(result.data()); 
    return result; 
} 

diğer fonksiyonlara referanslarla biraz karışık sorun http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qsharedpointer_impl.h?h=v5.5.1#n420 gibi görünüyor

https://bugreports.qt.io/browse/QTBUG-14637 olan basitleştirilmiş kod şöyle görünür (çoğunlukla aynı dosyada), ancak deleter'un yapıcı new yerleşimine göre çağrılmadan önce result içinde saklandığı anlaşılıyor. Yapıcınız atarsa, nesneniz hiçbir zaman tam olarak inşa edilmez, ancak QSharedPointer result halihazırda oluşturulmuştur ve deliciyi içerir. senin yapıcı tamamlamış asla rağmen,

static void deleter(ExternalRefCountData *self) 
{ 
    ExternalRefCountWithContiguousData *that = 
      static_cast<ExternalRefCountWithContiguousData *>(self); 
    that->data.~T(); 
} 

Ve şimdi yıkıcınız denir: Oradan deleter işlevine kısa bir hop. Bu tanımlanmamış bir davranış. Eğer şanssızsanız, bu durum uygulama durumunuzu bozacaktır (çünkü bir kurucunun yalnızca bir kurucu tamamlanmaya çalıştığı zaman çağrıldığı - bazı sınıf türlerinin güvenebileceği bir kuraldır).

muhtemel bir (ı test etmedim ama sen yapabilirsin) düzeltmedir: Yukarıdaki doğrulamak, bir yama içine örgü ve göndermektir çekinmeyin

static void noOpDeleter(ExternalRefCountData *self) 
{ 
    Q_UNUSED(self); 
} 

static inline QSharedPointer create() 
{ 
    typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private; 
    typename Private::DestroyerFn noDestroy = &noOpDeleter; 
    typename Private::DestroyerFn destroy = &Private::deleter; 

    QSharedPointer result(Qt::Uninitialized); 
    result.d = Private::create(&result.value, noDestroy); 

    new (result.data()) T(); 
    result.d->destroyer = destroy; 
    result.d->setQObjectShared(result.value, true); 
    result.enableSharedFromThis(result.data()); 
    return result; 
} 

Qt hata izleyici. Umarım çalışan bir yama ile derhal kabul ederler.

+0

Şanssızlık almaz: Canlı olmayan bir nesnenin yıkıcısını çağırmak tanımlanmamış bir davranıştır. Bir nesnenin ömrü, yapıcısı başarıyla tamamlandıktan sonra başlar. Birçok durumda, bu UB zararsız olabilir, ama UB ne olursa olsun. – Yakk

+0

@Yakk: Bunun için sağol, cevabınızı sizin puanınızı yansıtacak şekilde güncelledim. –

-1

Son olarak, fixed! Sanırım Qt 5.8.2 veya Qt 5.9 olurdu.

Teşekkürler @JohnZwinck, senin fikrin iyi çalışıyor.

İlgili konular