2010-10-31 15 views
5

Bir RAII nesnesi yapıyorum ve bu nesne yapılamıyor olabilir. Bunu nasıl halledebilirim? Bir RAII nesnesi oluşturulamadığında

try { 
    std::vector<int> v(LOTS); 
    // try scope ends here because that's what the catch is for 
} catch(const std::bad_alloc&) { 
    // ... 
} 
// v? what v? 

std::vector varsayılan kurucu atmaz ve bu yardımcı olabilir, Verilen, ancak bu genel bir durum değildir. Bir kurucu çok iyi atabilir. Herhangi bir kaynak edinme hatasıyla başa çıkmak istiyorsam, atma yapmıyorsa devam edebilmek için bunu nasıl yapabilirim?

Düzeltme: Açıklığa kavuşturmak gerekirse, bir kaynak edinme başarısız olursa, tekrar denemek isteyebilirim. Belki alternatif bir kaynak edinmeyi deneyebilirim.

+1

tam emin değilim. V kullanan kod, try bloğunda olmalıdır. – Dialecticus

+2

Soruyu anladığım gibi, 'v' yapıcısındaki bir istisnadan kurtulabilmek için, 'v'' try' kapsamının içinde beyan edilmek zorundadır; * catch * bloğundan sonra * görünür. Yani eğer bir elinizde v vekili oluştururken bir istisnayı "göz ardı edebilecek" ve eğer diğer yandan da "v" yi kullanabiliyorsa, bu biraz zorlaşırsa – jalf

+0

Kaynak edinme başarısız olur, ancak istisna yayılmasına izin vermektense bunun yerine başka bir kaynakla yapabilirim. Ve eğer bu ikinci kaynak başarısız olursa belki başka bir fikrim var, vb. Ne tür bir yaklaşım sergilediğim önemli değil. RAII, arızanın nasıl giderileceğini değil, arıza durumunda nasıl temizleneceğini açıklar. – wilhelmtell

cevap

7

"Devam" ile ne kastettiğinize bağlı. İşlem ne olursa olsun, kaynak başarısız olur: "gerektiren" bu demektir. Bu durumda onlarla yapabileceğiniz değerli bir şey (Rapor arızası olduğunda yalnızca durumları yakalamak neden

void something_using_RAII(thingummy &t) { 
    vector<int> v(t.size_required); 
    // do something using v 
} 

... 

for each thingummy { 
    try { 
     something_using_RAII(this_thingummy); 
    } catch(const std::bad_alloc &) { 
     std::cerr << "can't manage that one, sorry\n"; 
    } 
} 

var Bu ve: Eğer bir hata sonra devam etmek istiyorum Yani zaman, böyle kod yazarken sonunda olabilir sonraki şeylere geçme).

Eğer başarısızlık tekrar denemek istiyorum, ama yapıcı başarısız olduğu takdirde ise başka bir şey başarısız değilse:

while(not bored of trying) { 
    bool constructor_failed = true; 
    try { 
     vector<int> v(LOTS); 
     constructor_failed = false; 
     // use v 
    } catch(...) { 
     if (!constructor_failed) throw; 
    } 
} 

Bu daha çok veya daha az nasıl std::new_handler çalışmalardır - işleyicisi içinde adı verilir Bir bayrak gerekmesine rağmen, benzer bir döngü yakalama maddesi.

Eğer başarısızlık farklı bir kaynak denemek istiyorsanız

:

try { 
    vector<int> v(LOTS); 
    // use v 
} catch(...) try { 
    otherthing<int> w(LOTS); 
    // use w 
} catch(...) { 
    // failed 
} 

temelde aynı kod olan "w" "içine kullanım v" ve ardından bir fonksiyonu haline planı ayrı ve iki yerden de çağırırsanız. Bu noktada fonksiyonunuz oldukça fazla.

+2

'+ 1 'tek başına. Yeterli programcılar buna dikkat etmiyor. Çok maalesef. – sbi

7

Bir RAII kurucusu atıyorsa, RAII nesnelerinin atma noktasından önce bağlı olduğu tüm kaynaklar düzgün bir şekilde temizlenecektir. C++ kuralları bunu garanti etmek için hassas bir şekilde tasarlanmıştır. senin v inşaat nedeniyle bad_alloc ait atarsa ​​

sonra try blokta öncesinde v kendi oluşturduğum RAII nesnesi düzgün temizlenecektir. Dolayısıyla, RAII'yi kullanmanız durumunda, RAII nesneleri sizin için temizleme işleminin üstesinden geldiğinden, bu nedenle try/catch/catch kullanım kılavuzuna ihtiyacınız yoktur. Eğer 'un bir nedenine ihtiyacınız varsa, yukarıdaki gibi, aşağıdaki gibi takas kullanabilirsiniz.

std::vector<int> v; 
try { 
    std::vector<int> vtry(LOTS); 
    v.swap(vtry); // no-throw 
} catch(const std::bad_alloc&) { 
    // ... 
} 
// v! 
+1

Bu temizlikle ilgili değil. RAII nesnesi başlatılamadığında bir şey yapmakla ilgilidir. Hiçbir şey yapmazsam istisna yayılır. İyi değil. Ya fonksiyonumun no-throw garantisi vermesi gerekiyorsa? RAII nesnesinin fırlatmayan bir kurucusu yoksa ne olur? – wilhelmtell

+0

Atmak istemeyen kurucu olmayan bir nesnenin kötü tasarlanmış olduğunu söyleyebiliriz. Bu iyi. Bu tavsiyeyi hiçbir zaman hiç görmedim, bu yüzden doğruysa onu yüzeye getirmek istiyorum. Aksi halde, herhangi bir kukla atabildiğinde durumu nasıl ele aldığınızı dinleyin. – wilhelmtell

+0

@wilhelmtell, "RAII nesnesinin atamayacağı bir kurucu yoksa ne olur?" -> Bence bütün kodu 'try' cümlesi içine koymalısın. Atış yapamayan bir kurucunun olmaması kötü bir tasarım olduğunu düşünmüyorum. Bazen iyi uymuyor olabilir. Ama böyle bir atış-atlama durumu mevcutsa faydalı buluyorum. Nesnenizi ayrıca nothrow varsayılan durumuna ("shared_ptr" gibi) sahip bir akıllı işaretçiye de sarabilirsiniz. Ama bence iğrenç olur. Tablolar ile düzgün bir şekilde yapılırsa, blokların C++ 'da sıfır yürütme maliyeti olduğunu deneyin. Bu son cümle için –

2

v oluşturulamıyorsa, v kullanmayı deneyen tüm kodlar çalıştırılamaz. v, v kodunun kullandığı kodun ardından catch'u, v numarası yoksa yürütmeye devam etmenin makul olduğu bir yere taşıyın.

+2

Sorun, anladığım kadarıyla, v yakalayıcısından atılan bir istisnayla ya da try bloğundaki diğer kodla yakalanamaz. –

+0

@Roger: Bu durumda (tüm RAII sınıflarının olmadığı, ince, fakat "takas" a dayanan bloke litb çözümü), "try {vektör v (LOTS) gibi rahatsız edici şeyler yazmanız gerekir; bool bayrağı = true; deneyin {use v; flag = false; yakalamak (...) {X}} yakalamak (...) {Y}. X, try bloğundaki diğer koddaki istisnaları işler, Y, kurucunun * ya da destroyerinin * v' ve X'den istisnalar üstlenir. Ancak, v'nin yıkıcısı atmamalı ve X'in istisnaları tanınmalıdır. bayrak tarafından. –

0

V kodunu kullanan tüm kodların try bloğunda olması gerekir.O zaman soru istisna attı kodunu daraltmak için nasıl ise, böyle öylesin try bloğundaki yerleri göstermek üzere bayrak çeşit kullanabilirsiniz: sorunun ne olduğunu

string flag; 
try 
{ 
    flag = "creating vector<int> v"; 
    std::vector<int> v(LOTS); 

    flag = "performing blaggity bloop"; 
    blaggity_bloop(); 

    flag = "doing some other stuff"; 
    some_other_stuff(); 
} 
catch(const std::bad_alloc&) 
{ 
    cerr << "Bad allocation while " << flag << endl; 
}