2009-05-15 17 views
8

'Bu' öğesini aşağıdaki koddaki başlatıcı listesinde başka bir nesneye geçirirken herhangi bir sorun var mı?bunu yapıcı başlatıcı listesinden geçirme

class Callback { public: virtual void DoCallback() = 0; }; 

class B 
{ 
    Callback& cb; 
public: 
    B(Callback& callback) : cb(callback) {} 
    void StartThread(); 

    static void Thread() 
    { 
     while (!Shutdown()) 
     { 
      WaitForSomething(); 
      cb.DoCallback(); 
     } 
    } 
}; 

class A : public Callback 
{ 
    B b; 
public: 
    A() : b(*this) {b.StartThread();} 
    void DoCallback() {} 
}; 

Bunu yapmak güvenli değilse, en iyi alternatif nedir?

cevap

10

bu iyi çalışır son derece dikkatli değilseniz. Sanal yöntemleri çağırmaya veya türdeki diğer nesnelere bağımlı olan yöntemleri kullanmaya başladığınızda çok fazla sorun yaşayacaksınız. Ama sadece bir referans oluşturuyorsanız bu iyi çalışmalıdır.

Daha güvenli (ama tamamen güvenli değil) alternatif yapıcı tamamlandığında daha sonra b ayarlamaktır. Bu, geçerli sorunları ortadan kaldırmaz, ancak oluşturulmadan önce diğer üye değişkenlere erişim gibi sorunları giderir.

class A : public Callback { 
    std::auto_ptr<B> spB; 
public: 
    A() { 
    spB.reset(new B(this)); 
    spB->StartThread(); 
    } 
}; 
0

Referansın hala geçerli olduğundan emin olduğunuz sürece, bu, çift gönderim adı verilen bir deyime çok benzer. Bu durumda aşırı bir olasılık olabilir, ancak bununla ilgili yanlış bir şey yok. Diğer sınıf sadece durumda gibi işaretçi/başvuru, depolar ise

6

, bu güvenlidir. Ancak this'u geçen kurucuların/işlevlerin, A yapıcısının kurucusu bitmeden önce başvurulan nesneye erişmeye çalışmadığından emin olmalısınız. A nesnesi henüz tam olarak oluşturulmamış ve A yöntemlerini çağırıp özelliklerine erişme tanımsız sonuçlara neden olabilir. Eğer daha sonra kullanmak için sadece işaretçiyi saklıyorsanız, genellikle güvenlidir.

4

Bunu yaptım. Ben Aşağıdakilerden herhangi yapmazdı:

  • polimorfik şey yapın (onların kurucular vardı olmayabilir çalıştırmak)

    • tabanı veya türetilmiş sınıf verilerine erişmek için kullanın vtable başlatılmamış olabilir.

    Here, kuruculardaki "bu" ile ilgili sorunları detaylandıran C++ SSS'den harika bir makaledir.

  • +1

    , C++ SSS büyük makale göç etmiştir [buradan] (https: // isocpp .org/wiki/sss/vektörlerin içine klonlanabilir # kullanarak-bu-in-vektörlerin içine klonlanabilir) – peterpi

    2

    Size this nesne henüz tam inşa edilmemiştir unutmayın sağlanan yeterince güvenlidir. B sınıfınız, işaretçiyi, kurucunun herhangi bir işlevini çağırmadan depolarsa, güvende olursunuz. İşaretçiye Bütçe kurucusundan erişmeye çalışırsanız, son derece dikkatli olmanız ve A'nın üyelerinin başlatıldığı sıraya dikkat etmeniz gerekir.

    3

    hala altı inşaat nesne kodu çalıştırmak kurucular olarak mesajları Başlangıç ​​tehlikelidir. Sunulan kod, gerektiği gibi çalışır, ancak çözüm kırılgandır.

    DoCallbackA'da sanal bir yöntemi çağırırsa, iş parçacığının ne kadar hızlı çalıştığına bağlı olarak beklenmedik sonuçlarla sonuçlanabilir. Eğer denilen yöntem saf sanal ise, uygulama ölecektir, eğer saf değilse, türetilmiş versiyon yerine yöntemin A versiyonu çağrılacaktır. Bu, bir kurucudan asla sanal bir yöntemi asla çağırmamanız için aynı nedendir.

    daha güvenli bir yaklaşım kullanıcı parçacığı çağrı yaşıyor. Bu ayrıca boost :: thread library ve yaklaşan standarttaki yaklaşımdır.Oluşturma ve çalışan iş parçacığı iletecek sonra infaz ve olacak nesneyi başlatmak:

    Bazen o zaman ve şimdi arasında
    class Worker 
    { 
    public: 
        void DoWork(); 
    }; 
    void startWorkerThread() 
    { 
        Worker w; // fully create the object that is going to be run before you... 
        boost::thread thr(boost::bind(&Worker::DoWork, &w)); // ...create thread and run 
    }