SORU
23 Mart 2010, Salı


C Singleton deseni

Singleton deseni hakkında bir sorum var.

İki durumda singleton sınıfının statik üye ile ilgili gördüm.

İlk nesne, bu gibi

class CMySingleton
{
public:
  static CMySingleton& Instance()
  {
    static CMySingleton singleton;
    return singleton;
  }

// Other non-static member functions
private:
  CMySingleton() {}                                  // Private constructor
  ~CMySingleton() {}
  CMySingleton(const CMySingleton&);                 // Prevent copy-construction
  CMySingleton& operator=(const CMySingleton&);      // Prevent assignment
};

Bir işaretçi, gibi

class GlobalClass
{
    int m_value;
    static GlobalClass *s_instance;
    GlobalClass(int v = 0)
    {
        m_value = v;
    }
  public:
    int get_value()
    {
        return m_value;
    }
    void set_value(int v)
    {
        m_value = v;
    }
    static GlobalClass *instance()
    {
        if (!s_instance)
          s_instance = new GlobalClass;
        return s_instance;
    }
};

İki dava arasındaki fark nedir? Hangisi doğru?

CEVAP
23 Mart 2010, Salı


Muhtemelen Alexandrescu kitap okumalısın.

İlgili yerel statik görmedim Visual Studio için bir süre, ama ne zaman derleme ile Visual Studio 2003, ' bir yerel statik tahsis başına DLL... konuşmak hakkında bir kabus hata ayıklama bunu unutmam için bir süre :/

1. Bir Tek ömür boyu

Tekiz ile ilgili temel sorun, ömür boyu yönetimidir.

Eğer hiç bir nesne kullanmayı deneyin, canlı ve hareketli olmak gerekir. Sorun böylece bütünsel C ile ortak bir sorun olan başlatma ve imha.

Başlatma genellikle düzeltmek için en kolay şeydir. Her iki yöntem de önerdiği gibi, ilk kullanımda başlatmak için yeteri kadar basit.

Bu yıkım biraz daha hassas. genel değişkenler oluşturulduğu ters sırada yok. Yerel statik durumda, aslında her şeyi kontrol edemezsin...yani.

2. Yerel bir statik

struct A
{
  A() { B::Instance(); C::Instance().call(); }
};

struct B
{
  ~B() { C::Instance().call(); }
  static B& Instance() { static B MI; return MI; }
};

struct C
{
  static C& Instance() { static C MI; return MI; }
  void call() {}
};

A globalA;

Burada sorun nedir ? Yani kurucular ve yıkıcılar olarak sipariş bakalım.

İlk olarak, inşaat aşamasında:

  • A globalA; yürütülür
  • A::A() B::B() çağırır
  • A::A() C::C() çağırır

B C ilk giriş örneklerini biz başlatılamıyor, çünkü gayet iyi çalışıyor.

İkincisi, yıkım aşaması

  • C::~C() son 3 inşa edilmiştir, çünkü denir
  • B::~B() adlı... oops, 19**'örneği ! erişmeye çalışır.

Biz böylece yıkım, hum, tanımsız davranış

3. Yeni strateji

Buradaki fikir basit. built-ins işaretçiyi yazdığınız kodun herhangi bir adlı önce 0 set olacak diğer bütünsel önce başlatılan, küresel, test sağlar:

S& S::Instance() { if (MInstance == 0) MInstance = new S(); return *MInstance; }

Ya bu örneği doğru olup olmadığını kontrol eder aslında.

Ancak, orada bir bellek sızıntısı burada ve en kötü söylenmiş asla çağrılan bir yıkıcı. Çözüm var, ve standart. atexit işlev çağrısı.

atexit fonksiyon yürütmek için bir eylem belirtin program kapatma sırasında izin ver. Bu, tek bir iyi yazabiliriz:

// in s.hpp
class S
{
public:
  static S& Instance(); // already defined

private:
  static void CleanUp();

  S(); // later, because that's where the work takes place
  ~S() { /* anything ? */ }

  // not copyable
  S(S const&);
  S& operator=(S const&);

  static S* MInstance;
};

// in s.cpp
S* S::MInstance = 0;

S::S() { atexit(&CleanUp); }

S::CleanUp() { delete MInstance; MInstance = 0; } // Note the = 0 bit!!!

İlk olarak, daha fazla atexit hakkında bilgi edinin. İmza argüman olarak bir şey alır bir işlev için bir işaretçi kabul eder ve hiçbir şey döndürür int atexit(void (*function)(void)); ıe.

Nasıl çalışır ? Bir işlev işaretçisi yığın aramak kurar ve imha sırasında bir kerede tek bir öğe yığını dökülür de başlatma. tam olarak önceki kullanım örneği: Bu durumda, bu fonksiyon Son-İlk-bir şekilde aradı.

İşte o zaman ne olur ?

  • İlk erişim (başlatma ince) inşaat, çıkış zamanı CleanUp yöntemi kayıt olurum

  • Çıkış süresi: CleanUp yöntemi çağrılır. Nesne (böylece etkili bir yıkıcı iş yapabiliriz) yok eder ve 0 işaretçiyi sıfırlama sinyali için.

Çoktan yok olmuş bir nesne örneği çağırıyorum (A, B C ile örnekte olduğu gibi) ne olur ? Geri 0 işaretçiyi kurduğumdan beri bu durumda, geçici bir singleton yeniden yapacağım ve yeni bir döngü başlıyor. Benim yığını depiling olduğum için uzun ama canlı değil.

Alexandrescu ile yok oldu sonra ihtiyaç halinde kendi küllerinden diriltiyor olarak Phoenix Singleton denir.

Başka bir seçenek var statik bir bayrak ve ayarlamak için destroyed sırasında temiz ve kullanıcı bilmediği bir örneğinin singleton, örneğin tarafından dönen bir boş gösterici. Bir işaretçi (referans) dönen, tek sorun daha iyi kimse: / delete Ara kadar aptal olmalısın

4. Monoid Desen

Singleton bahsederken Monoid Desen tanıtmanın zamanı geldi sanırım. Özünde, Flyweight desen, veya Singleton Proxy bir kullanım dejenere bir durum olarak görülebilir.

Basit Monoid desen: sınıf payı tüm örneklerini sık karşılaşılan bir durum.

-Phoenix uygulanmasını göstermek için bu fırsatı:) ederim

class Monoid
{
public:
  void foo() { if (State* i = Instance()) i->foo(); }
  void bar() { if (State* i = Instance()) i->bar(); }

private:
  struct State {};

  static State* Instance();
  static void CleanUp();

  static bool MDestroyed;
  static State* MInstance;
};

// .cpp
bool Monoid::MDestroyed = false;
State* Monoid::MInstance = 0;

State* Monoid::Instance()
{
  if (!MDestroyed && !MInstance)
  {
    MInstance = new State();
    atexit(&CleanUp);
  }
  return MInstance;
}

void Monoid::CleanUp()
{
  delete MInstance;
  MInstance = 0;
  MDestroyed = true;
}

Peki ne yararı var ? Gizler devlet paylaştırılmış olması, Singleton gizler.

  • Eğer hiç gerek yok 2 ayrı devletler, mümkün olduğunu göreceksiniz yönetmek olmadan değişen her satır kod kullanılır (değiştirme Singleton bir ara Factory örneğin)
  • Nodoby senin singleton delete örnek arayacak, gerçekten devleti yönetmek ve kazaları önlemek yani... çok kötü niyetli kullanıcılara karşı yine de yapamazsın!
  • Tekil erişim kontrol, yok oldu sonra deniyor diye doğru bir şey yapmak, günlük, vb...) işleyebilir

5. Son bir söz

Bu görünse de tam, mutlu bir şekilde daha fazla bilgi edinmek için herhangi bir çoklu sorunları... read Alexandrescu Modern C yağsız olduğumu belirtmek isterim!

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • CNET

    CNET

    5 Mayıs 2006
  • InfinityWard

    InfinityWard

    19 EYLÜL 2006
  • pilslajt

    pilslajt

    20 HAZİRAN 2008