Anahtar kelimeyi işlevin imzasına atın


200

throwBir işlev imzasında C ++ anahtar sözcüğünü kullanmanın kötü uygulama olarak kabul edilmesinin teknik nedeni nedir ?

bool some_func() throw(myExc)
{
  ...
  if (problem_occurred) 
  {
    throw myExc("problem occurred");
  }
  ...
}

Bu son ilgili soruya bakın: stackoverflow.com/questions/1037575/…
laalto


1
Bir noexceptşey değiştirir mi?
Aaron McDaid

12
Programlama ile ilgili bir şey hakkında görüş sahibi olmanın yanlış bir yanı yoktur. Bu kapanış kriterleri en azından bu soru için kötü. İlginç cevapları olan ilginç bir soru.
Anders Lindén

İstisna belirtimlerinin C ++ 11'den beri kullanım dışı kaldığına dikkat edilmelidir .
François Andrieux

Yanıtlar:


127

Hayır, iyi uygulama olarak kabul edilmez. Aksine, genellikle kötü bir fikir olarak kabul edilir.

http://www.gotw.ca/publications/mill22.htm neden hakkında daha fazla ayrıntıya girer, ancak sorun kısmen derleyicinin bunu uygulayamamasıdır, bu nedenle çalışma zamanında kontrol edilmelidir, bu genellikle istenmeyen. Ve her durumda iyi desteklenmemektedir. (MSVC, istisna atılmayacağının bir garantisi olarak yorumladığı throw () dışında istisna özelliklerini yoksayar.


25
Evet. Kodunuza boşluk eklemenin (myEx) yönteminden daha iyi yolları vardır.
Assaf Lavie

4
evet, sadece istisna özelliklerini keşfeden insanlar genellikle derleyicinin bunları uygulayabildiği Java gibi çalıştıklarını varsayarlar. C ++ 'da bu olmayacak, bu da onları daha az kullanışlı hale getiriyor.
jalf

7
Peki ya belgesel amaç? Ayrıca, deneseniz bile hangi istisnaları asla yakalayamayacağınız size söylenecektir.
Anders Lindén

1
@ AndersLindén hangi belgesel amaç? Kodunuzun davranışını belgelemek istiyorsanız, üzerine bir yorum yazmanız yeterlidir. İkinci bölümle ne demek istediğinizden emin değilim. Deneseniz bile asla yakalamayacağınız istisnalar?
jalf

4
Kodunuzu belgelemek söz konusu olduğunda kodun güçlü olduğunu düşünüyorum. (yorumlar yalan söyleyebilir). Bahsettiğim "belgesel" etki, hangi istisnaları yakalayabileceğinizden ve başkalarının yapamayacağından emin olacaksınız.
Anders Lindén

57

Jalf zaten ona bağlıydı, ancak GOTW , istisna özelliklerinin neden umduğu kadar yararlı olmadığını oldukça iyi bir şekilde ortaya koyuyor:

int Gunc() throw();    // will throw nothing (?)
int Hunc() throw(A,B); // can only throw A or B (?)

Yorumlar doğru mu? Pek değil. Gunc()gerçekten bir şey fırlatabilir ve Hunc()A veya B dışında bir şey fırlatabilir! Derleyici, eğer yaparlarsa, onları anlamsız yenmeyi ve programınızı da anlamsız bir şekilde yenmeyi garanti eder.

Bu sadece aşağıya iniyor, muhtemelen sadece bir çağrı ile terminate()sonuçlanacaksınız ve programınız hızlı ama acı verici bir ölümle ölüyor.

GOTW'ların sonucu:

İşte bugün bir topluluk olarak öğrendiğimiz en iyi tavsiye gibi görünen:

  • Ahlaki # 1: Asla bir istisna belirtimi yazmayın.
  • Ahlaki # 2: Muhtemelen boş olan hariç, ama ben olsaydım bundan bile kaçınırdım.

1
Neden bir istisna atacağım ve bundan söz edemeyeceğimden emin değilim. Başka bir işlev tarafından atılansa bile, hangi istisnaların atılabileceğini biliyorum. Görebilmemin tek nedeni sıkıcı olması.
MasterMastic

3
@Ken: Mesele şu ki, istisna şartnameleri yazmanın çoğunlukla olumsuz sonuçları vardır. Tek olumlu etki, programcıya hangi istisnaların meydana gelebileceğini göstermesidir, ancak derleyici tarafından makul bir şekilde kontrol edilmediğinden hatalara yatkındır ve bu nedenle çok fazla değmez.
sth

1
Oh tamam, cevap verdiğin için teşekkürler. Sanırım bu belgelerin ne için olduğunu.
MasterMastic

2
Doğru değil. İstisna belirtimi yazılmalıdır, ancak fikir, arayanın hangi hataları yakalamaya çalışması gerektiğini bildirmektir.
HelloWorld

1
@StudentT'in söylediği gibi: başka istisnalar atmamak garanti altına almak işlevin sorumluluğundadır. Eğer yaparlarsa, program olması gerektiği gibi sona erer. Atışı beyan etmek, bu durumu ele almak benim sorumluluğum değildir ve arayan kişinin bunu yapmak için yeterli bilgiye sahip olması gerekir. İstisnaları bildirmemek, her yerde meydana gelebilecekleri ve herhangi bir yerde ele alınabilecekleri anlamına gelir. Bu kesinlikle anti-OOP karmaşası. Yanlış yerlerde istisnaları yakalamak tasarım başarısızlığıdır. İstisnalar istisnai olduğu ve çoğu işlev yine de boş bırakılacağı için boş atmamanızı tavsiye ederim.
Jan Turoň

30

Bu soruya verilen diğer tüm yanıtlara biraz daha fazla değer katmak için, soruya birkaç dakika yatırım yapılması gerekir: Aşağıdaki kodun çıktısı nedir?

#include <iostream>
void throw_exception() throw(const char *)
{
    throw 10;
}
void my_unexpected(){
    std::cout << "well - this was unexpected" << std::endl;
}
int main(int argc, char **argv){
    std::set_unexpected(my_unexpected);
    try{
        throw_exception();
    }catch(int x){
        std::cout << "catch int: " << x << std::endl;
    }catch(...){
        std::cout << "catch ..." << std::endl;
    }
}

Cevap: As kaydetti burada , program çağrıları std::terminate()ve istisna işleyicileri dolayısıyla hiçbiri adlı.

Ayrıntılar: İlk my_unexpected()işlev çağrılır, ancak throw_exception()işlev prototipi için eşleşen bir özel durum türünü yeniden atmadığından , sonunda, işlev std::terminate()çağrılır. Yani tam çıktı şöyle görünür:

kullanici @ kullanici: ~ / tmp $ g ++ -o hariç.test hariç.test.cpp
kullanici kullanici: kullanici: ~ / tmp $ ./except.test
iyi - bu
bir 'int'
Durduruldu (çekirdek terk)


12

Atış belirtecinin tek pratik etkisi, myExcişlevinizden farklı bir şey atılırsa, std::unexpectedçağrılacaktır (normal işlenmeyen istisna mekanizması yerine).

Bir işlevin atabileceği istisna türlerini belgelemek için genellikle bunu yaparım:

bool
some_func() /* throw (myExc) */ {
}

5
Std :: unexpected () öğesine yapılan bir çağrının genellikle std :: terminate () çağrısına ve programınızın aniden sona erdiğine dikkat etmek de yararlıdır.
sth

1
- ve MSVC en azından bildiğim kadarıyla bu davranışı uygulamaz.
jalf

9

Dile atış özellikleri eklendiğinde en iyi niyetleri vardı, ancak uygulama daha pratik bir yaklaşım ortaya koydu.

C ++ ile genel kuralım yalnızca bir yöntemin atamadığını belirtmek için fırlatma özelliklerini kullanmaktır. Bu güçlü bir garantidir. Aksi takdirde, herhangi bir şey atabileceğini varsayın.


9

Peki, bu atış spesifikasyonu hakkında googling yaparken, bu makaleye bir göz attım: - ( http://blogs.msdn.com/b/larryosterman/archive/2006/03/22/558390.aspx )

Burada da bir kısmını yeniden üretiyorum, böylece yukarıdaki bağlantının çalışıp çalışmadığına bakılmaksızın gelecekte kullanılabilir.

   class MyClass
   {
    size_t CalculateFoo()
    {
        :
        :
    };
    size_t MethodThatCannotThrow() throw()
    {
        return 100;
    };
    void ExampleMethod()
    {
        size_t foo, bar;
        try
        {
            foo = CalculateFoo();
            bar = foo * 100;
            MethodThatCannotThrow();
            printf("bar is %d", bar);
        }
        catch (...)
        {
        }
    }
};

Derleyici, "throw ()" özniteliğiyle bunu gördüğünde, derleyici "bar" değişkenini tamamen optimize edebilir, çünkü MethodThatCannotThrow () yönteminden bir kural dışı durumun atılmasının bir yolu olmadığını bilir. Throw () özniteliği olmadan, derleyici "bar" değişkenini oluşturmak zorundadır, çünkü MethodThatCannotThrow bir istisna atarsa, istisna işleyici çubuk değişkeninin değerine bağlı olabilir / olacaktır.

Buna ek olarak, prefast gibi kaynak kodu analiz araçları, hata algılama yeteneklerini geliştirmek için throw () ek açıklamasını kullanabilir (örneğin, bir try / catch'ınız varsa ve çağırdığınız tüm işlevler throw () olarak işaretlenmişse, try / catch'e ihtiyacınız yoktur (evet, daha sonra fırlatabilecek bir işlevi çağırırsanız bunun bir sorunu vardır).


3

Yalnızca üye değişkeni döndüren ve muhtemelen istisnaları atlayamayan eğik bir işlevde bir atım belirtimi , bazı derleyiciler tarafından performans üzerinde zararlı bir etkiye sahip olabilecek kötümsemeler (optimizasyonların tersi için yapılmış bir sözcük) için kullanılabilir. Bu Boost literatüründe tanımlanmıştır: İstisna spesifikasyonu

İle bazı derleyiciler doğru optimizasyonlar yapılmış ve bunu haklı bir şekilde bu fonksiyon etkiler performansının kullanılması halinde olmayan içi işlevler üzerinde herhangi bir atış özellikleri yararlı olabilir.

Bana göre, belki de profil oluşturma araçları kullanarak, bir performans optimizasyonu çabasının bir parçası olarak çok eleştirel bir göz tarafından yapılan bir çağrıdır.

Acele edenler için yukarıdaki bağlantıdan bir alıntı ( saf bir derleyiciden bir satır içi işlev üzerine atma belirtmenin kötü istenmeyen etkilerine bir örnek içerir ):

İstisna belirtimi gerekçesi

İstisna spesifikasyonları [ISO 15.4] bazen hangi istisnaların atılabileceğini belirtmek için kodlanır veya programcı performansı arttırmayı umduklarından. Ancak akıllı bir işaretçiden aşağıdaki üyeyi düşünün:

T & operatörü * () const throw () {dönüş * ptr; }

Bu işlev başka hiçbir işlevi çağırmaz; yalnızca işaretçiler gibi temel veri türlerini değiştirir. Bu nedenle, istisna belirtiminin çalışma zamanı davranışı hiçbir zaman çağrılamaz. Fonksiyon tamamen derleyiciye açıktır; gerçekten de satır içi olarak bildirildi Bu nedenle, akıllı bir derleyici, işlevlerin istisnaları atmaktan aciz olduğunu kolayca belirleyebilir ve boş istisna spesifikasyonuna dayanarak yaptığı aynı optimizasyonları yapabilir. Ancak "aptal" bir derleyici her türlü kötümserlik yapabilir.

Örneğin, bir istisna belirtimi varsa bazı derleyiciler satır sonunu kapatır. Bazı derleyiciler try / catch blokları ekler. Bu tür kötümsemeler, kodu pratik uygulamalarda kullanılamaz hale getiren bir performans felaketi olabilir.

Başlangıçta cazip olmasına rağmen, bir istisna belirtimi, çok dikkatli düşünmeyi gerektiren sonuçlara sahip olma eğilimindedir. İstisna belirtimlerindeki en büyük sorun, programcıların bunları, gerçekte sahip oldukları etki yerine programcının istediği etkiye sahipmiş gibi kullanmalarıdır.

Satır içi olmayan bir işlev, "hiçbir şey atmaz" özel durum özelliğinin bazı derleyicilerle bazı faydaları olabileceği yerdir.


1
"İstisna belirtimlerindeki en büyük sorun, programcıların bunları, gerçekte sahip oldukları etki yerine programcının istedikleri etkiye sahipmiş gibi kullanmalarıdır." Makinelerle veya insanlarla iletişim kurarken hataların 1 numaralı nedeni budur: söylediğimiz ve ne demek istediğimiz arasındaki fark.
Thagomizer
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.