2015-02-05 38 views
7
#include <memory> 
#include <iostream> 

struct A : public std::enable_shared_from_this<A> 
{ 
    ~A() 
    { 
     auto this_ptr = shared_from_this(); // std::bad_weak_ptr exception here. 
     std::cout << "this: " << this_ptr; 
    } 
}; 

int main() 
{ 
    auto a = std::make_shared<A>(); 
    a.reset(); 
    return 0; 
} 

shared_from_this() numaralı telefonu arayarak std::bad_weak_ptr istisnası alıyorum. Tasarım gereği mi? Evet, bu işaretçi destroyerin geri döndükten sonra kullanılamayacağı için tehlikeli olabilir, ancak işaretçiyi buraya almak için teknik olarak imkansız bir neden göremiyorum çünkü paylaşılan işaretçi nesnesi hala var ve Kullanılmış. Bunu atlatmanın herhangi bir yolu var mı, kendi enable_shared_from_this analogumu yazmam (kısa bir süre yapmamayı tercih ediyorum)?std :: enable_shared_from_this: destroctor'da shared_from_this() öğesini çağırmasına izin verilir mi?

+0

http://stackoverflow.com/q/8501503/1147772 – Drax

+0

@Drax: Bu soruyu gördüm. Bu, 'std' değil 'destek' ile ilgilidir ve cevaplar 'shared_from_this()' kullanılabilirliği üzerindeki temel sınırlamalardan ziyade söz konusu kodun özel tasarımı hakkında konuşur. –

+0

@VioletGiraffe Soru, ne “ne” ne de “std”, sadece zayıf referans kavramıyla ilgilidir. – curiousguy

cevap

6

Ben paylaşılan işaretçi nesne belli ki hala var ve kullanılabilir, çünkü burada işaretçi almak için teknik olarak imkansız bir neden görmüyorum. bu mümkün değil neden

çok iyi teknik sebebi yok.

shared_ptr olabilir, ancak A nesnesi için referans sayısı sıfıra ulaştı, bu nedenle destructor çalıştırılıyor. başvuru sayısı ulaştığında tekrar arttırılamaz sıfır kez (aksi takdirde kendi yıkıcı çalışan ortasında dir, ya da daha önce tahrip edilmiş bir nesne anlamına gelmektedir, bir shared_ptr alabilir).

shared_from_this() çağrısı, başvuru sayısını artırmaya ve geçerli sahip (ler) ile sahipliğini paylaşan bir shared_ptr döndürmeye çalışır, ancak sayacı sıfırdan bire çıkaramazsınız, bu nedenle başarısız olur. yılında

(nesnenin yıkıcısı içinde) bu çok özel durum nesne henüz tam tahrip edilmemiş biliyorum ama shared_from_this() işlevini arayanın kim olduğunu hiçbir şekilde enable_shared_from_this<A> vardır, bu yüzden eğer bilemez 'da bu çok özel durumda veya nesnenin yıkıcısı dışında başka bir kod parçası (örn. yıkıcıdan sonra devam edecek başka bir iş parçacığında).

Bir şekilde bu özel durum için çalışabilir ve şu anda yok edilen nesneyi başvurulan bir shared_ptr<A> var, bu shared_ptr daha sonra kullanmak üzere saklanan yok edici dışında bir şey verebilirsiniz. Bu, diğer kod parçasının, nesne yok edildikten sonra sarkan bir shared_ptr'a erişmesine izin verir. Bu, shared_ptr ve weak_ptr tip sisteminde büyük bir delik olur.

+0

Harika bir açıklama, teşekkürler. –

0

shared_ptr::reset bireyin uygulanması genellikle shared_ptr().swap(*this) olduğunu. shared_ptr Eğer sırayla sizin yıkıcı çağırmadan önce paylaşılan sayısı azaltma kendi yıkıcı durum zaten kopyalamaya çalıştığınız anlamına

. Eğer enable_shared_from_this çağırdığınızda sayımı 0.

Yani soruya cevap olduğunda böylece bir özel durum olduğunu weak_ptr bir shared_ptr oluşturarak weak_ptr bunun içinde depolanan teşvik çalışacağız, yapmanın standart bir yolu yoktur ne standart kitaplık uygulamanızın yetkilendirecek şekilde davranmamasını istersiniz (standart tarafından zorunlu olup olmadığını bilmiyorum).

Şimdi

, burada benim makinede (çınlama/libC++) üzerinde çalışır kesmek:

#include <memory> 
#include <iostream> 

class hack_tag 
{ 
}; 

namespace std 
{ 

    template<> 
    class shared_ptr<hack_tag> 
    { 
    public: 
    template<typename T> 
    weak_ptr<T>  extract_weak(const enable_shared_from_this<T>& shared) 
    { 
     return shared.__weak_this_; 
    } 
    }; 

}; 

using weak_ptr_extractor = std::shared_ptr<hack_tag>; 

class test : public std::enable_shared_from_this<test> 
{ 
public: 
    test() 
    { 
    std::cout << "ctor" << std::endl; 
    } 

    ~test() 
    { 
    std::cout << "dtor" << std::endl; 
    weak_ptr_extractor hacker; 
    auto weak = hacker.extract_weak(*this); 
    std::cout << weak.use_count() << std::endl; 
    auto shared = weak.lock(); 
    } 
}; 


int  main(void) 
{ 
    std::shared_ptr<test> ptr = std::make_shared<test>(); 

    ptr.reset(); 
} 

Ama sen senin kopyaladığınız shared_ptr sahibi beri bununla kullanışlı her şeyi yapabilir emin yaklaşık edilir değilim ölmek ve bu kopya reset aramadan sonra yeni temiz shared_ptr ile şeyler paylaşmaz.

9

[util.smartptr.enab]/7 shared_from_this önşartlarını açıklanmaktadır:

gerektirir:enable_shared_from_this<T>T erişilebilir bir temel sınıf olacaktır. *this tip T bir nesne t bir subobject olacaktır. &t sahibi en az bir shared_ptr örneği p bulunacaktır . [emph. eklendi]

Nesneniz yok edildiğinden, sahip olduğu shared_ptr olması şart değildir. Sonuç olarak, tanımlanmamış davranışla sonuçlanan gereksinimi ihlal etmeden shared_from_this numaralı telefonu arayamazsınız.

+1

"Nesneniz yok edildiğinden, sahip olduğu" shared_ptr "değerinin olmaması gerekir." Birisi açık bir yıkıcı arama yapmak için yeterince çılgın değilse;) –

+1

@ T.C. Eğer durum buysa, o zaman “birileri”, açıkça, * onlar, aslında, nesneye atıfta bulunan 'shared_ptr'nın sahibi değillerdir. Benim argümanım;) – Casey

+0

Düşüncem, bir nesnenin imha edilmesinden 'shared_ptr' sorumlu olduğundan dolayı, işaretçi, tuttuğu nesne silinmeden _after_'e kadar imha edilmeyecekti. Ama görünüşe göre, referans sayım nesnesi, en azından MS uygulamasında, bundan önce yok edildi, bu yüzden, yok edicide zaten mevcut değil. –