C ++ 'da "bir işlevi zehirlemek" ne anlama gelir?


96

Scott Schurr'ın CppCon'daki "Tanıtıcı constexpr" konuşmasının en sonunda , "Bir işlevi zehirlemenin bir yolu var mı?" Diye soruyor. Daha sonra bunun (standart olmayan bir şekilde de olsa) şu şekilde yapılabileceğini açıklar:

  1. throwBir constexprişlevi bir işleve koymak
  2. Çözülmemiş ilan etmek extern const char*
  3. Çözülmemiş başvurulması externhalindethrow

Burada derinliğimden biraz uzak olduğumu hissediyorum ama merak ediyorum:

  • "Bir işlevi zehirlemek" ne anlama gelir?
  • Ana hatlarını çizdiği tekniğin önemi / faydası nedir?

1
Bu terimi hiç duymadım, lütfen kısa bir örnekle açıklayın!
πάντα ῥεῖ

6
@ πάνταῥεῖ, sadece açıklığa kavuşturdum. Bu, 'küçük çevrelerde yaygın olarak bilinen' bir terim
SergeyA

4
İşleve yapılan her çağrının constexprderleme zamanında değerlendirilmesini sağlamaktan bahsediyor .
TC

@TC Right - bir constexprfonksiyonun derleme zamanında veya çalışma zamanında kullanılabileceğinden bahsetti . Yani bu onu çalıştırma zamanında kullanamayacak şekilde zorlamanın bir yolu mu? Bu ne zaman işe yarar?
sudo make install

3
Özellikle C ++ 11'de, bir constexprişlev kısıtlamalar nedeniyle çoğu zaman en verimli uygulama değildir, bu nedenle çalışma zamanında değerlendirilmesi istenmeyebilir; veya belki de hata durumudur (örneğindeki gibi).
TC

Yanıtlar:


106

Genel olarak, bir işlevi kullanılamaz hale getirmeyi ifade eder, örneğin, bir programda dinamik ayırmanın kullanımını yasaklamak istiyorsanız, mallocişlevi "zehirleyerek" kullanılamaması için "zehirleyebilirsiniz" .

Videoda bunu daha spesifik bir şekilde kullanıyor. Bu, işlevi zehirlemekten bahsederken görüntülenen slaydı okursanız, "Yalnızca derleme zamanını zorlamanın bir yolu mu?"

Bu nedenle, işlevi çalışma zamanında çağrılamaz hale getirmek için "zehirlemekten" bahsediyor, bu nedenle yalnızca sabit ifadelerde çağrılabilir. Teknik, işlevde derleme zamanı bağlamında çağrıldığında asla alınmayan bir dalın olması ve bu dalın bir hataya neden olacak bir şey içermesini sağlamaktır.

Bir throwconstexpr işlevinde bir ifadeye, işlevin derleme zamanı çağrısı sırasında asla ulaşılmadığı sürece izin verilir (çünkü derleme zamanında bir istisna atamazsınız, bu, bellek ayırma gibi, doğası gereği dinamik bir işlemdir). Bu nedenle tanımlanmamış bir sembole atıfta bulunan bir atma ifadesi, derleme zamanı çağrıları sırasında kullanılmaz (çünkü bu derleme başarısız olur) ve tanımsız sembol bir bağlayıcı hatasına neden olduğundan çalışma zamanında kullanılamaz.

Tanımlanmamış sembol, fonksiyonun derleme zamanı çağrılmasında "odr tarafından kullanılmış" olmadığından, pratikte derleyici sembole bir referans oluşturmayacaktır, bu nedenle tanımsız olması sorun değildir.

Bu yararlı mı? Bunun nasıl yapılacağını gösteriyor , bunun iyi bir fikir olduğunu veya yaygın olarak yararlı olduğunu söylemiyor. Herhangi bir nedenle bunu yapmanız gerekiyorsa, tekniği probleminizi çözebilir. İhtiyacınız yoksa endişelenmenize gerek yok.

O bir nedeni olabilir bazı operasyonun derleme zamanı sürüm değil olması gerektiği kadar etkili olduğu zaman uygun bir çözüm olabilir. Bir constexpr işlevinde izin verilen ifade türlerinde kısıtlamalar vardır (özellikle C ++ 11'de, C ++ 14'te bazı kısıtlamalar kaldırılmıştır). Dolayısıyla, bir hesaplama yapmak için bir işlevin iki sürümüne sahip olabilirsiniz, biri optimal olan, ancak bir constexpr işlevinde izin verilmeyen ifadeler kullanan ve diğeri de geçerli bir constexpr işlevi olan, ancak çalıştırıldığında çağrılırsa kötü performans gösterir zaman. Çalışma zamanı çağrıları için asla kullanılmamasını sağlamak için optimumun altında olanı zehirleyebilir ve çalışma zamanı çağrıları için daha verimli (constexpr olmayan) sürümün kullanılmasını sağlayabilirsiniz.

NB Derleme zamanında kullanılan bir constexpr işlevinin performansı gerçekten önemli değildir, çünkü zaten çalışma zamanı ek yükü yoktur. Derleyicinin fazladan iş yapmasını sağlayarak derlemenizi yavaşlatabilir, ancak herhangi bir çalışma zamanı performans maliyeti olmayacaktır.


1
Slaydın metnini okudum, ancak kullandığı terimle bağlantısını görmedim. Şimdi açıkladığın çok açık, ama o zaman görmedim. Bu mükemmel cevap için çok teşekkürler - Bu web sitesini çok seviyorum.
sudo make install

@PravasiMeet, kendi sorunuzu sorun, başka birinin farklı bir şey hakkındaki sorusunun yorumlarını kaçırmayın. Basit bir çözüm, onu her çeviri biriminde silinmiş olarak tanımlamak veya tanımlanmamış bir sembole atıfta bulunan kendi tanımınızla değiştirmek olabilir.
Jonathan Wakely

17

Bir tanımlayıcıyı 'zehirlemek', 'zehirlemeden' sonra tanımlayıcıya yapılan herhangi bir göndermenin zor bir derleyici hatası olduğu anlamına gelir. Bu teknik, örneğin, zor kullanımdan kaldırma için kullanılabilir (işlev IS kullanımdan kaldırılmıştır, asla kullanmayın!).

In GCC geleneksel olarak bunun için bir Pragma vardı: #pragma GCC poison.


1
Evet, ama tam olarak bu konuşmada kullanılan anlamda değil.
TC

@TC, tamam, muhtemelen cevaplamadan önce
izlemeliyim
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.