İstisna güvenliğini C ++ kodunuzda ne kadar önemli buluyorsunuz?


19

Kodumu kesinlikle istisna olarak güvenli hale getirmeyi her düşündüğümde, bunu yapmamayı haklı çıkarıyorum çünkü çok zaman alıcı olurdu. Bu nispeten basit snippet'i düşünün:

Level::Entity* entity = new Level::Entity();
entity->id = GetNextId();
entity->AddComponent(new Component::Position(x, y));
entity->AddComponent(new Component::Movement());
entity->AddComponent(new Component::Render());
allEntities.push_back(entity); // std::vector
entityById[entity->id] = entity; // std::map
return entity;

Temel bir istisna garantisi uygulamak için newaramalarda kapsamlı bir işaretçi kullanabilirim. Bu, aramalardan herhangi biri bir istisna atacaksa bellek sızıntılarını önleyecektir.

Ancak, güçlü bir istisna garantisi uygulamak istediğimi varsayalım. En azından, kaplarım Entity::Swapiçin paylaşılan bir işaretçi (Boost kullanmıyorum), bileşenleri atomik olarak eklemek için bir not ve hem Vectorve hem de atomik olarak eklemek için bir tür deyim uygulamak gerekir Map. Bunların uygulanması sadece zaman alıcı olmakla kalmaz, aynı zamanda güvensiz çözümden çok daha fazla kopyalama gerektirdiğinden pahalı olurlar.

Nihayetinde, tüm bunları yapmak için harcanan zamanın haklı olmayacağı gibi hissediyorum CreateEntity fonksiyonun istisnai olarak güvenli . Muhtemelen oyunun bir hata göstermesini ve yine de o noktada kapanmasını istiyorum.

Kendi oyun projelerinizde bunu ne kadar ileri taşıyorsunuz? Sadece bir istisna olduğunda çökebilecek bir program için istisna güvensiz kod yazmak genellikle kabul edilebilir mi?


21
Geçmişte C ++ projelerinde çalıştığımda, temelde istisnalar yokmuş gibi davrandık.
Tetrad

2
Şahsen, istisnaları seviyorum ve genellikle kodumun nasıl güçlü garantiler sağlayacağını bulmanın tadını çıkarıyorum. Yine de bir istisna aldığınızda çarpacaksanız ... belki bununla uğraşmayın.

7
Ben şahsen hatalar değil .. hm .. 'istisnalar' yönetmek için istisnalar kullanın. Gibi, eğer bir fonksiyon çökebilir biliyorum, ben çökmesine izin, ama eğer bir fonksiyon başarıyla bir arşiv okumak olmayabilir biliyorum, ama başka bir yolu var, ben bir deneyin ile yakalamak, yakalamak. ve onun bir "okuyamıyor" istisnası, ben sadece arşiv okuma olmadan yapacağım başka bir şekilde yönetmek.
Gustavo Maciel

Gtoknu'nun söylediği gibi, herhangi bir dış kütüphanecinin hangi istisnaları atabileceğinin farkında olmanız gerekir.
Peter Ølsted

Yanıtlar:


26

İstisnalar kullanacaksanız (bu, yapmanız gerektiği anlamına gelmez, bu sorunun özel kapsamının dışında olan bu yaklaşımın artıları ve eksileri vardır), istisna güvenli kodunu düzgün bir şekilde yazmalısınız.

İstisnaları kullanmayan ve açıkça istisna güvenli olmayan kod, bunları kullanan koddan daha iyidir, ancak istisna güvenliğini yarıya indirir. İkinci durumunuz varsa, büyük olasılıkla hiç kurtulamayacağınız bir istisna meydana geldiğinde oluşabilecek bir hata ve başarısızlık sınıfınız vardır, bu da istisnaların yararlarından birini tamamen boş ve geçersiz kılar. Nispeten nadir bir başarısızlık sınıfı olsa bile, hala mümkündür.

Bu, istisnalar kullanırsanız, tüm kodun güçlü istisna garantisini sağlaması gerektiği anlamına gelmez - sadece her kod parçası bir tür garanti sağlamalıdır (hiçbiri, temel, güçlü), böylece bu kodun tüketimi tüketicinin size hangi garantileri sağlayacağını biliyorsunuz. Genellikle söz konusu bileşen ne kadar düşük seviyede olursa, garanti o kadar güçlü olmalıdır.

Hiçbir zaman güçlü bir garanti sunmayacaksanız veya istisna işleme paradigmalarını ve bununla ilgili tüm ekstra iş ve dezavantajları asla benimsemeyecekseniz, ima ettiği tüm avantajları gerçekten elde edemezsiniz ve daha kolay olabilirsiniz. zaman sadece istisnalar tamamen devam ediyor.


12
Bu tek başına bir +1 değerinde: "İstisnalar kullanmayan ve açıkça istisna güvenli olmayan kod, bunları kullanan koddan daha iyidir, ancak istisna güvenliğini yarıya indirir."
Maximus Minimus

14

Genel kuralım: İstisnalar kullanmanız gerekiyorsa istisnalar kullanın. İstisnalar kullanmanız gerekmiyorsa, istisnalar kullanmayın. İstisnaları kullanmanız gerekip gerekmediğini bilmiyorsanız, istisnaları kullanmanız gerekmez.

İstisnalar, her zaman görev açısından kritik uygulamalarda mutlak son savunma hattınız olacaktır. Kesinlikle başarısız olamayacak hava trafik kontrol yazılımı yazıyorsanız, istisnalar kullanın. Bir nükleer santral için kontrol kodu yazıyorsanız, istisnalar kullanın.

Bir oyun geliştirirken, diğer taraftan, mantrayı takip etmekten çok daha iyidir: Erken çarp, yüksek sesle çarp. Bir sorun varsa, bunu mümkün olan en kısa sürede bilmek istersiniz; hataların hiçbir zaman görünmez bir şekilde 'ele alınmasını' istemezsiniz, çünkü bu genellikle daha sonraki hatalı davranışların gerçek nedenini gizleyecek ve hata ayıklamayı olması gerekenden çok daha zorlaştıracaktır.


5

İstisnalar ile ilgili sorun zaten onlarla başa çıkmak zorunda. Belleğiniz yetersiz olduğu için bir istisna alıyorsanız, bu hatayı yine de işleyemeyebilirsiniz. Ayrıca tüm oyunu bir hata kutusu açan 1 dev istisna işleyicisine dökün.

Oyun geliştirme için, kodumu nezaketle başarısızlıkla devam ettirmenin yollarını bulmaya çalışmayı tercih ediyorum.

Örneğin oyunuma özel bir HATA mesh kodlayacağım. Üzerinde beyaz bir X ve beyaz bir sınır bulunan dönen bir kırmızı daire. Oyuna bağlı olarak görünmez olan daha iyi olabilir. Başlangıçta başlatılan tek bir tek örneği vardır. Harici dosyalar kullanmak yerine koda dönüştürüldüğünden, başarısız olması mümkün olmamalıdır.

Normal bir loadMesh çağrısı, bazı hataları geri atmak ve masaüstüne çökmek yerine başarısız olursa, sessizce konsolu / log dosyasına kaydeder ve sabit kodlu hata ağını döndürür. Bir modun işleri mahvettiğinde Skyrim'in aslında aynı şeyi yaptığını öğrendim. Oyuncunun hata ağını bile görmeyeceği iyi bir olasılık var (bazı büyük problemler yoksa ve birçoğu böyle değilse).

Bir yedek gölgelendirici de var. Temel köşe matrisi işlemlerini yapan, ancak bir nedenden dolayı tekdüze bir matris yoksa, yine de dik görünümü yapmalıdır. Uygun gölgeleme / aydınlatma / malzeme içermez (her ne kadar bir color_overide bayrağı olsa da, hata ağımla kullanabilirsiniz).

Tek olası sorun, hata mesh sürümünün oyunu kalıcı olarak bir şekilde kırabilirse. Örneğin, oyuncu bir alan yüklerse, o zaman içindeki hata örgüsü yere düşebilir, o zaman oyunu bu sefer doğru örgü çalışmasıyla yeniden yüklerse, daha büyükse, toprağa gömülü. Muhtemelen çok zor olmamalı çünkü muhtemelen fizik ağlarınızı grafiklerinizle birlikte saklayacaksınız. Komut dosyası oluşturma da bir sorun olabilir. Bazı şeylerle sadece sert ölmek zorunda kalacaksın. Gerçekten bir geri dönüş 'seviyesi' ne kullanmak emin değilim (bir hata olduğunu söyleyerek bir işaret ile küçük bir oda yapabilir, sadece oyuncu içine sıkışmış istemiyorum çünkü kaydetme devre dışı olduğundan emin olun).

'Yeni' durumunda, oyun geliştirme için bir tür fabrika kullanmaya bakmak daha iyi olabilir. Nesneleri gerçekten ihtiyaç duymadan önce önceden konumlandırmak ve / veya toplu hale getirmek gibi çeşitli avantajlar sağlayabilir. Ayrıca, bellek yönetimi için kullanabileceğiniz, kimliğe göre bir şeyler bulabileceğiniz global bir nesne dizini gibi şeyleri daha kolay hale getirir (bunu yapıcılarda da yapabilirsiniz). Ve tabii ki orada da tahsis hatalarını işleyebilirsiniz.


2

Eksik çalışma zamanı denetimleri ve çökmeleri ile ilgili en büyük şey, bir hacker'ın işlemi ve belki de daha sonra makineyi ele geçirmek için bir çökme kullanması potansiyelidir.

Şimdi, bir bilgisayar korsanı gerçek bir kazadan yararlanamaz, kaza meydana gelir gelmez süreç işe yaramaz ve zararsızdır. Eğer boş bir göstergeden okursanız, bu temiz bir çökmedir, bir hata yaparsınız ve işlem anında ölür.

Tehlike, teknik olarak yasa dışı olmayan, ancak yapmak istediğiniz şey olmadığında ortaya çıktığında, bir bilgisayar korsanı, aksi takdirde güvenli olması gereken özenle hazırlanmış veriler kullanarak bu eylemi yönlendirebilir.

Yakalanmamış bir istisna aslında gerçek bir çökme değil, programı sonlandırmanın bir yoludur. İstisnalar yalnızca birileri belirli koşullar altında özel bir istisna oluşturan bir kütüphane yazdığı için olur. Tipik olarak, bir hacker için bir açılış olabilecek beklenmedik bir duruma girmekten kaçınmak.

Aslında, tehlikeli hamle, kaymalarına izin vermek yerine istisnaları yakalamaktır, yani bunu asla yapmamanız gerektiği anlamına gelmez, ancak sadece işleyebileceğiniz ve geri kalanının kaymasına izin verdiğinizi yakaladığınızdan emin olun. Aksi takdirde, kitaplığınıza dikkatlice yerleştirilen güvenlik önlemini geri alma riskiyle karşı karşıya kalırsınız.

Bir dizinin sonunun ötesinde yazmak gibi istisnalar atmaya gerek olmayan hatalara odaklanın. Programınız şans eseri bunu yapamaz mı?


2

İstisnalarınıza ve onları tetikleyebilecek koşullara bakmanız gerekir. Geliştirme / hata ayıklama oluşturma / test döngüsü sırasında insanların istisnalar için kullandıkları şeylerin büyük bir yüzdesi, doğru kontrollerle önlenebilir. Ekleri kullanın, referansları kullanın, her zaman bildirimde yerel değişkenleri başlatın, memset-zero tüm tahsisleri, ücretsiz sonra NULL, vb. Ve çok sayıda teorik istisna vakası sadece ortadan kalkar.

Şunu düşünün: bir şey başarısız olursa ve bir istisna atmaya aday olabilirse - etkisi nedir? Ne kadar önemli? Bir oyunda (orijinal örneğinizi almak için) bir bellek ayırmada başarısız olursanız, genellikle elinizde başarısızlık durumunu nasıl ele aldığınızdan daha büyük bir sorununuz vardır ve başarısızlık durumunu bir istisna aracılığıyla ele almak daha büyük bir sorun yaratmaz. çekip gitmek. Daha da kötüsü, aslında daha büyük sorunun bile orada olduğu gerçeğini gizleyebilir. Bunu istiyor musun? Yapmadığımı biliyorum. Bir bellek ayırmada başarısız olursam, çökmek ve korkunç bir şekilde yanmak ve hata noktasına mümkün olduğunca yakın yapmak istiyorum, böylece hata ayıklayıcıya girebilir, neler olduğunu anlayabilir ve düzgün bir şekilde düzeltebilirim.


1

Başka birine alıntı yapmanın SE için uygun olup olmadığından emin değilim ama diğer cevapların hiçbiri gerçekten buna dokunmadı.

Jason Gregory'den Game Engine Architecture kitabından alıntı . (HARİKA KİTAP!)

"Yapılandırılmış özel durum işleme (SEH) programlamak için çok fazla ek yük ekler. Her yığın çerçevesi, yığın çözme işleminin gerektirdiği ek bilgileri içerecek şekilde genişletilmelidir. Ayrıca, yığın çözme işlemi genellikle çok yavaştır. Programınızdaki (veya kütüphanenizdeki) bir işlev bile SEH kullanıyorsa, tüm programınız SEH kullanmalıdır Derleyici, çağrı yığınında hangi işlevlerin üstünüzde olabileceğini bilemez. bir istisna atarsınız. "

Bununla birlikte, inşa ettiğim motorum istisna kullanmıyor. Bunun nedeni, daha önce bahsedilen potansiyel performans maliyeti ve tüm amaçlar için hata dönüş kodlarının iyi çalışmasıdır. Gerçekten başarısızlıkları aramaya ihtiyacım olan tek zaman kaynakları başlatmak ve yüklemek ve bu durumlarda başarıyı gösteren bir boole döndürmek iyi çalışıyor.


2
Yapılandırılmış özel durum işleme, Windows'ta kullanılabilen, genellikle C ++ özel durumlarıyla aynı olmayan belirli bir özel durum işleme türüdür.
Kylotan

Doh, bunu bilmediğime inanamıyorum. Düzeltme için teşekkürler!
KlashnikovKid

0

Her zaman bir istisna oluşturulduğunda veya yakalandığında bir şey kaydedebildiğim için, kod istisnasını her zaman güvenli hale getiriyorum, çünkü problemlerin nerede ortaya çıktığını daha kolay biliyor.

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.