Bir başlatma yöntemine sahip olmaktan kaçının


12

Nerede bir sınıf ve bu sınıfta bir başlatma yöntemi var bu mevcut kodu var. Sınıfın nesnesi oluşturulduktan sonra, bu nesneye onun üzerinde başlat çağrısı yapmaları beklenir.

Başlatma yönteminin var olmasının nedeni Nesne genel bir kapsama sahip olmak için erken oluşturulur ve sonra başlatma yöntemi daha sonra bağımlı olduğu bir dll yüklendikten sonra çağrılır.

Başlatma işlemiyle ilgili sorun Sınıf artık, ilerlemeden önce her yöntemde kontrol edilmesi gereken ve başlatılmamışsa hata döndüren bu boole isInitialized'e sahip. Basitçe söylemek gerekirse, bu büyük bir acıdır.

Olası bir çözüm Yapıcıda başlat. Global kapsamda nesneye sadece bir işaretçi var. Dll yüklendikten sonra gerçek nesneyi oluşturun.

Yukarıdaki çözümle ilgili sorun Bu sınıfın bir nesnesini oluşturan herkes, yalnızca dll yüklendikten sonra oluşturulması gerektiğini bilmelidir, aksi takdirde başarısız olur.

Bu kabul edilebilir mi?


OpenGL bağlamı oluşturulmadan önce somutlaştırılması gereken OpenGL ile ilgili nesneler oluştururken de aynı sorunu yaşadım, ancak

3
Aptalca soru # 1: Nesne oluşturucu DLL'i önceden yüklenmemişse neden yükleyemiyor?
John R. Strohm

1
Eski bir soruyu yeniden canlandırdığınız için özür dileriz, ancak 2017 yılında birisinin bunu okuması durumunda C ++ 11'de kullanıncall_once . Henüz C ++ 11 üzerinde olmayan projeler, call_once'un C ++ 11'de nasıl uygulandığını (çözdüğü soruna ve sonra nasıl yapıldığına odaklan) incelemeli ve sonra C ++ 'ın (eski) lezzetinde yeniden uygulamalıdır. Durumunun statik olarak başlatılması gereken (sabit bir değerle) çok iş parçacıklı güvenli bir senkronizasyon ilkesine ihtiyacı vardır. C ++ 11 öncesi derleyicilerin karşılanması gereken başka özdeşliklere sahip olabileceğini unutmayın.
rwong

Yanıtlar:


7

Sanal bir proxy için bir iş gibi geliyor.

Söz konusu nesneye başvuru içeren bir sanal proxy oluşturabilirsiniz. DLL yüklenmemişken, Proxy istemcilere belirli varsayılan davranışlar sunabilir, DLL yüklendikten sonra proxy tüm istekleri gerçek konuya yönlendirir.

Sanal proxy DLL başlatmayı denetlemekten sorumlu olacak ve buna dayanarak isteğin gerçek konuya devredilmesi gerekip gerekmediğine karar verecek.

Wikipedia'da proxy kalıbı

Bu fikri nasıl buldunuz?


burada çok fazla çözmezsin. gerçek nesneye eklenen her yöntem için bu yöntemi proxy'ye de eklemeniz gerekir. Hayır?

Bu, initi çağırmayı hatırlama problemini önler. işlev, ancak proxy'deki her işlevin hala .dll'nin yüklü olup olmadığını kontrol etmesi gerekiyor gibi görünüyor.

1
@Sriram şimdi büyük bir fark var, bir proxy kullanarak DLL kontrol ile ilgili bakım tek bir sınıfa kısıtladı: proxy. Sınıfın istemcilerinin DLL denetimi hakkında bilgi sahibi olması gerekmez. Çoğu yöntem yetki devri yapacağından, ara yüzün vekil sunucunun her iki gerçek öznesinde uygulanmasında çok fazla sorun görmüyorum. Başka bir deyişle, DLL'nin yüklendiğinden emin olana kadar gerçek konunun oluşturulmasını önleyebilirsiniz ve daha sonra her seferinde DLL durumunu kontrol etmeniz gerekmez.

@edalorzo: fikir iyi olsa da, burada sorun zaten bir vekil hakkında konuşuyoruz ve OP vekilinin her yöntemini kontrol etmek zorunda şikayet ediyor ...
Matthieu M.

4

DLL henüz yüklenmemişse yararlı bir şey olmaz; nesne yalnızca bir hata oluşturur. Önemli bir hata mı? Hata nasıl ele alınır?

Test metodolojiniz bu hatanın bitmiş üründe asla meydana gelmemesini sağlıyor mu?

Mimari tasarım için değil, test için bir iş gibi geliyor. Sadece bir hata döndürmeyin, assertasla olmayacak.

Şu anda hatayı yakalayıp yok sayan sınıftaki istemcileri, ilk etapta denemeye ve neden olmayacak şekilde düzeltin.

Çok iş parçacıklı bir desen, DLL yüklendikten sonra paylaşılan koşul değişkeni ayarlamak ve DLL yüklenene kadar nesnenin yapıcısının beklemesini (ve diğer iş parçacıklarını engellemesini) olabilir.


Doğru olduğunu düşünüyorum, DLL düzgün başlatılmamışsa söz konusu nesnenin oluşturulması üzerine bir istisna atma yanlış bir şey yok. Müşteri kodunun yalnızca bu istisna ile uğraşması gerekir ve test, istisnanın uygun şekilde ele alınmasını sağlamalıdır.

2

İlk şey: durumları asla değişmediği sürece (yapılandırma) küresel nesnelerden zararlı olarak kaçının.

Şimdi, eğer ona takılı kalırsanız, herhangi bir nedenle, muhtemelen size yardımcı olabilecek birkaç tasarım var.

İki fikir buldum:

  1. DLL yüklemek için bir cephe kullanın. Nesneye yalnızca Cephe üzerinden erişilebilir, Cephe, aynı zamanda Nesnenin oluşturulması ve başlatılması üzerine DLL'yi yükler.

  2. Bir Proxy kullanın, ancak akıllı tür;)

İkinci noktada ayrıntıya gireyim , çünkü @edalorzo'nun cevabının sizi korkutmasından korkuyorum:

// Private
static Object& GetObjectImpl() { static Object O; return O; }

// Public
static Object& GetObject() {
  Object& o = GetObjectImpl();
  assert(o.isInitialized() && "Object not initialized yet!");
  return o;
}

Artık tek bir çekiniz var.

Bu, bir tür akıllı işaretçi ile de yapılabilir:

Pointer<Object> o;

Burada yalnızca başlangıçta null olan bir işaretçi için yer ayırırsınız ve yalnızca DLL yüklendiğinde nesneyi ayıracaksınız. Önceki tüm erişimler bir istisna (NullException: p?) Oluşturmalı veya programı sonlandırmalıdır (temiz).


1

Bu aldatıcı bir soru. Mimarlığın soruna yardımcı olabileceğini düşünüyorum.

Kanıt olarak, program yüklendiğinde .dll yüklenmemiş gibi görünüyor. Neredeyse bir eklenti gibi geliyor.

Akla gelen bir şey .dll başlatmak zorunda olmasıdır. Programcı, nesnenin zaten güvenilir bir şekilde geri dönmeyeceğini varsaymalıdır. Bundan ( bool isObjectLoaded() { return isInitialized; }) faydalanabilirsiniz , ancak çekleriniz üzerinde kesinlikle daha fazla hata raporu alacaksınız.

Bir singleton düşünüyordum.

Singleton'u çağırırsanız, alabilecekleri doğru nesneyi döndürmelidir. Doğru nesneyi döndüremezse, bazı hata değeri / nullptr / empty temel nesnesi almalısınız. Nesne üzerinizde ölebilirse bu işe yaramaz.

Ayrıca, nesnenin birden çok örneğine ihtiyacınız varsa, bunun yerine Fabrika gibi bir şey kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.