yeni std :: istisna atma std :: istisna


113

rastladığım bazı koda bakarken:

throw /*-->*/new std::exception ("//...

ve her zaman newburada ihtiyacın olmadığını / kullanmaman gerektiğini düşündüm .
Doğru yol nedir, ikisi de tamam mı, eğer öyleyse herhangi bir fark var mı?

PowerShell ile "grep" yaparken görebildiğim kadarıyla BTW destek kitaplıkları asla kullanmaz throw new.

PS ayrıca kullanan bazı CLI kodu buldum throw gcnew. Tamam mı?


1
throw gcnewÖrneğin yararlı olacağını düşünüyorum . yönetilen kodun istisnanızı yakalamasını istiyorsanız. Biri beni bu konuda düzeltebilir mi?
jpalecek

1
.Net, istisnalarla işaretçi ile ilgilenir, bu nedenle gcnew atmak orada yapılacak doğru şeydir.
Sebastian Redl

1
@SebastianRedl .Net "işaretçi" belirsiz olabilir mi? Gcnew kesinlikle değil. System::Exceptiongenellikle çöp toplanan yığın üzerindeki yönetilen bir nesneye referanstır. Her zaman birlikte fırlattım gcnewve yakaladım System::Exception ^. Tabii ki finallyher zaman C ++ / CLI'de de kullanıyorum, ancak aynı trybloktaki C ++ istisnaları ile sık sık karıştırmıyorum, neden olduğundan emin değilim.

Yanıtlar:


89

İstisnaları atmanın ve yakalamanın geleneksel yolu, bir istisna nesnesi atmak ve onu referansla yakalamaktır (genellikle const referansla) . C ++ dili, derleyicinin istisna nesnesini oluşturmak için uygun kodu oluşturmasını ve uygun zamanda düzgün bir şekilde temizlemesini gerektirir.

Dinamik olarak ayrılmış bir nesneye bir işaretçi fırlatmak asla iyi bir fikir değildir. İstisnaların, hata durumları karşısında daha sağlam kod yazmanıza olanak sağlaması beklenir. Geleneksel bir şekilde bir istisna nesnesi atarsanız, doğru türü adlandıran bir catch cümlesine yakalanmış catch (...)olup olmadığından, daha sonra yeniden fırlatılıp atılmayacağından emin olabilirsiniz, uygun zamanda doğru şekilde imha edilecektir. (Tek istisna, hiç yakalanmamasıdır, ancak bu, hangi şekilde bakarsanız bakın kurtarılamaz bir durumdur.)

Dinamik olarak tahsis edilmiş bir nesneye bir işaretçi atarsanız, istisnanızı atmak istediğiniz noktada çağrı yığını nasıl görünürse görünsün, doğru işaretçi tipini adlandıran ve uygun deleteçağrıya sahip bir yakalama bloğu olduğundan emin olmalısınız . İstisnanız, catch (...)bu blok istisnayı yeniden atmadıkça, daha sonra istisna ile doğru şekilde ilgilenen başka bir yakalama bloğu tarafından yakalanmadıkça asla yakalanmamalıdır .

Etkili bir şekilde, bu, sağlam kod yazmayı kolaylaştıracak ve her durumda doğru olan kodu yazmayı çok zorlaştıracak istisna işleme özelliğini aldığınız anlamına gelir. Bu, bu özelliği beklemeyen istemci kodu için kütüphane kodu olarak hareket etmenin neredeyse imkansız olacağı sorununu bir kenara bırakıyor.


1
"bir istisna nesnesi fırlat" yığını mı yoksa yığın mı arkadaşımı? Yığın mı yoksa yığın mı? (Belki bir yerde kötü bir küresel örneğe bakıyordum) oh ve eğer yığılırsa, o zaman uygun kapsam nedir?

@ebyrob: Ne sorduğunuzu tam olarak bilmiyorum ama burada yanıtlanabilecek istisna nesnesinin depolanması ve / veya ömrü hakkında bilgi edinmek istediğiniz gibi görünüyor . Değilse, ayrı bir soru sormanız daha iyi olabilir.
CB Bailey

31

newİstisna atarken kullanmaya gerek yok .

Sadece yaz:

throw yourexception(yourmessage);

ve şu şekilde yakalayın:

catch(yourexception const & e)
{
      //your code (probably logging related code)
}

Doğrudan veya dolaylı olarak yourexceptiontüretilmesi gerektiğini unutmayın std::exception.


7
Neden? neden kullanmıyorsun new? neden türetmek yourexceptiondan std::exception?
Walter

Tembel olduğumda (ki bu çoğu zaman beklenir) neden çalışmıyor throw std::exception;? g ++ onu

7
@ebyrob: std::exceptiontürüdür ve bir atamaz türünü size atılan bir etmek, ettik nesne . Yani sözdizimi şu olmalıdır: throw std::exception();Bu derlenecek. Şimdi bunun ne kadar iyi olduğu, tamamen farklı bir sorudur.
Nawaz

22

Fırlatma new std::exceptionçağrı site bir yakalamak için bekliyor eğer doğruysa std::exception*. Ancak hiç kimse bir istisnayı göstermeyi beklemeyecektir. İşlevinizin yaptığını belgeleseniz ve insanlar belgeleri okusalar bile, yine de unutmak ve std::exceptionbunun yerine bir nesneye referans yakalamaya çalışmakla yükümlüdürler .


27
Fırlatma new std::exceptionyalnızca, arama sitesi bir işaretçi yakalamayı bekliyorsa VE tahsis istisnasının yönetimini devralmayı bekliyorsa VE hiçbir zaman işlevinizin açıkça yakalanmayan bir şey tarafından çağrılmayacağı durumlar olmayacaksa doğrudur. doğru işaretçi ( catch(...)veya hiç işleme yok) aksi takdirde bir nesne sızıntısı olacaktır. Kısacası, bu "hiçbir zaman" olarak tahmin edilebilir.
CB Bailey

Bu cevabın nasıl kabul edildiğini merak ediyor, gerçekten @ CharlesBailey'nin yorumu doğru cevap.
John Dibling

@John: Bu da aklımdan geçti. Ama bir-iki yumruğunun benim kuru özet vermemde ve Charles'ın eğlenceli bir şekilde insanların bununla düzgün bir şekilde başa çıkmayı unutabilecekleri çeşitli yolları genişletmesinde iyi bir etkisi olduğunu düşünüyorum. Ne yazık ki, oy alan yorumlardan itibar kazanmıyorsunuz.

Charles cevabını vermedi ve bu A'nın (diğerinin aksine) hem A'da hem de yorumda açıklamaları var.
NoSenseEtAl

9

C ++ SSS'nin bu konuda güzel bir tartışması var:

  1. https://isocpp.org/wiki/faq/exceptions#what-to-catch
  2. https://isocpp.org/wiki/faq/exceptions#catch-by-ptr-in-mfc

Temel olarak, "referansla yakalamamak için iyi bir neden olmadıkça. Değere göre yakalamaktan kaçının, çünkü bu bir kopyanın yapılmasına neden olur ve kopya atılandan farklı davranışlara sahip olabilir. Sadece çok özel koşullar altında işaretçi ile yakalamalısınız. "


2
Her zamanki gibi, SSS kötü bir şekilde ifade edilmiştir. Değere veya referansa göre yakalayabilirsiniz. Bir işaretçi sadece bir değerdir (değere veya referansa göre yakaladığınız). Türün türden Afarklı olduğunu unutmayın, A*bu yüzden eğer yaparsam tamamen farklı bir tür olduğu için throw A()yakalayamam catch(A* e).
Martin York

Bu bağlantılar artık kopmuştur.
stephenspann

1
@Spanndemic
user1202136

1

Yeni operatör, hiçbir zaman bir istisna oluşturmayacağını garanti edemez. Bu nedenle, "geçerli" (amaçlanan) bir istisna atmak için kullanılması, çökmemesi garanti edilemeyen bir kod üretir. Her seferinde sadece bir istisna olabileceğinden ve programınız bunlardan herhangi biri yakalanmadan önce iki tane atmaya çalıştığından, bir gerçeklemenin yapabileceği en iyi şey, örneğin std :: terminate çağırarak programınızı derhal iptal etmektir.

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.