Yığın gevşemesi nedir? Arandı, ancak aydınlatıcı bir cevap bulamadık!
Yığın gevşemesi nedir? Arandı, ancak aydınlatıcı bir cevap bulamadık!
Yanıtlar:
Yığın gevşemesi genellikle istisna işleme ile bağlantılı olarak konuşulur. İşte bir örnek:
void func( int x )
{
char* pleak = new char[1024]; // might be lost => memory leak
std::string s( "hello world" ); // will be properly destructed
if ( x ) throw std::runtime_error( "boom" );
delete [] pleak; // will only get here if x == 0. if x!=0, throw exception
}
int main()
{
try
{
func( 10 );
}
catch ( const std::exception& e )
{
return 1;
}
return 0;
}
Burada pleak
bir istisna atılırsa ayrılan bellek kaybolur, buna ayrılan bellek her durumda yıkıcı s
tarafından düzgün bir şekilde serbest bırakılır std::string
. Kapsamdan çıkıldığında yığına ayrılan nesneler "çözülür" (burada kapsam fonksiyonun içindedir func
.) Bu, derleyici otomatik (yığın) değişkenlerin yıkıcılarına çağrı ekleyerek yapılır.
Şimdi bu, C ++ 'da bellek, veritabanı bağlantıları, açık dosya tanımlayıcıları, vb. Gibi kaynakları yönetmemize yardımcı olan RAII adı verilen , yani Kaynak Alımı Başlatma tekniğine giden çok güçlü bir kavramdır .
Şimdi bu, istisna güvenlik garantileri sağlamamıza izin veriyor .
delete [] pleak;
yalnızca x == 0 ise ulaşılır.
Bütün bunlar C ++ ile ilgilidir:
Tanım : Nesneleri statik olarak oluştururken (yığın belleğinde yığın belleğine ayırmak yerine) ve işlev çağrıları gerçekleştirdikçe "yığılır".
Bir kapsamdan ( {
ve sınırlandırılmış herhangi bir şey }
) çıkıldığında ( return XXX;
kapsamın sonuna ulaşarak veya bir istisna atarak) bu kapsamdaki her şey yok edilir (her şey için yıkıcılar çağrılır). Yerel nesneleri yok etme ve yıkıcıları çağırma işlemine yığın çözme denir.
Yığın çözme ile ilgili aşağıdaki sorunlarınız var:
bellek sızıntılarından kaçınmak (dinamik olarak ayrılan ve yerel bir nesne tarafından yönetilmeyen ve yıkıcıda temizlenen herhangi bir şey sızdırılır) - Nikolai tarafından atıfta bulunulan RAII'ye ve boost :: scoped_ptr veya boost :: mutex kullanma örneğine bakın :: scoped_lock .
program tutarlılığı: C ++ belirtimleri, varolan herhangi bir özel durum işlenmeden önce hiçbir zaman özel durum atmamanız gerektiğini belirtir. Bu , yığın çözme işleminin hiçbir zaman istisna atmaması gerektiği anlamına gelir (ya sadece yıkıcılara atmama garantili kodu kullanın ya da try {
ve ile yıkıcılardaki her şeyi çevreleyin } catch(...) {}
).
Herhangi bir yıkıcı yığın gevşetme sırasında bir istisna atarsa , programınızın beklenmedik bir şekilde (en yaygın davranış) veya evrenin sona ermesine (teorik olarak mümkün ancak henüz uygulamada gözlemlenmemiş) sonlanmasına neden olabilecek tanımlanmamış davranış ülkesine girersiniz .
Genel anlamda, bir "gevşeme" yığını, bir işlev çağrısının sonu ve yığının sonraki patlamasıyla hemen hemen eş anlamlıdır.
Ancak, özellikle C ++ durumunda, yığın çözme, C ++ 'ın herhangi bir kod bloğunun başlamasından bu yana tahsis edilen nesneler için yıkıcıları nasıl çağırdığıyla ilgilidir. Blok içinde oluşturulan nesneler, ayırma işlemlerinin tersi sırada yeniden konumlandırılır.
try
Bloklar hakkında özel bir şey yok . Herhangi bir blokta (isteseniz de try
olmasın) ayrılan yığın nesneleri , blok çıktığında gevşeyebilir.
Yığın çözme, çoğunlukla C ++ konseptidir ve yığıntan ayrılmış nesnelerin kapsamından çıkıldığında (normal olarak veya bir istisna yoluyla) nasıl yok edildiğiyle ilgilenir.
Bu kod parçasına sahip olduğunuzu varsayalım:
void hw() {
string hello("Hello, ");
string world("world!\n");
cout << hello << world;
} // at this point, "world" is destroyed, followed by "hello"
Henüz okuyup okumadığınızı bilmiyorum ama Wikipedia'nın çağrı yığınıyla ilgili makalesi iyi bir açıklamaya sahip.
gevşemeden:
Aranan işlevden döndüğünüzde, üst kareyi yığının dışına çıkarabilir, belki de bir dönüş değeri bırakabilirsiniz. Programın başka bir yerinde yürütmeyi sürdürmek için bir veya daha fazla kareyi yığının dışına atmanın daha genel eylemi denir yığın çözme ve özel durum işleme için kullanılanlar gibi yerel olmayan kontrol yapıları kullanıldığında gerçekleştirilmelidir. Bu durumda, bir işlevin yığın çerçevesi özel durum işleyicilerini belirten bir veya daha fazla girdi içerir. Bir istisna atıldığında, atılan istisnanın türünü işlemek (yakalamak) için hazırlanmış bir işleyici bulunana kadar yığın açılır.
Bazı diller genel gevşemeyi gerektiren başka kontrol yapılarına sahiptir. Pascal, genel goto deyiminin, iç içe geçmiş bir işlevden ve önceden çağrılan bir dış işleve aktarılmasını sağlar. Bu işlem yığının açılmasını gerektirir ve kontrolü ekteki dış işlev içindeki hedef ifadeye aktarmak üzere uygun bağlamı geri yüklemek için gerektiği kadar yığın çerçevesini kaldırır. Benzer şekilde, C, lokal olmayan gotolar olarak işlev gören setjmp ve longjmp işlevlerine sahiptir. Common Lisp, çözme koruması özel operatörünü kullanarak yığın çözüldüğünde ne olacağını kontrol etmenizi sağlar.
Bir devam uygularken, yığın (mantıksal olarak) açılır ve daha sonra devam yığını ile geri sarılır. Sürekliliği uygulamanın tek yolu bu değildir; örneğin, birden çok açık yığın kullanarak, bir devamın uygulanması yığınını etkinleştirebilir ve geçirilecek bir değeri sarabilir. Şema programlama dili, bir devam çağrıldığında kontrol yığınının "gevşetilmesi" veya "geri sarılması" üzerinde belirtilen noktalarda keyfi seslerin yürütülmesine izin verir.
Muayene [değiştir]
Anlamama yardımcı olan bir blog yazısı okudum.
Yığın gevşemesi nedir?
Özyinelemeli işlevleri destekleyen herhangi bir dilde (yani Fortran 77 ve Brainf * ck hariç hemen hemen her şey), dil çalışma zamanı şu anda hangi işlevlerin yürütülmekte olduğunu bir yığın halinde tutar. Yığın çözme, bu yığını incelemenin ve muhtemelen değiştirmenin bir yoludur.
Bunu neden yapmak istiyorsun?
Cevap açık görünebilir, ancak gevşemenin yararlı veya gerekli olduğu birkaç ilişkili, ancak farklı derecede farklı durumlar vardır:
- Çalışma zamanı kontrol akış mekanizması olarak (C ++ istisnaları, C longjmp (), vb.).
- Hata ayıklayıcıda, kullanıcıya yığını göstermek için.
- Bir profil oluşturucuda, yığının bir örneğini almak.
- Programın kendisinden (yığını göstermek için bir kilitlenme işleyicisinden olduğu gibi).
Bunların çok farklı gereksinimleri vardır. Bunlardan bazıları performans açısından kritik, bazıları değil. Bazıları dış çerçeveden kayıtları yeniden oluşturma yeteneğini gerektirir, bazıları gerektirmez. Ama bir saniyede bütün bunlara gireceğiz.
Yayının tamamını burada bulabilirsiniz .
Herkes C ++ 'da istisna işleme hakkında konuştu. Ancak, yığın gevşemesi için başka bir çağrışım olduğunu düşünüyorum ve bu hata ayıklama ile ilgili. Bir hata ayıklayıcı, geçerli kareden önceki bir kareye gitmesi gerektiğinde yığın çözme işlemini yapmak zorundadır. Ancak bu, mevcut kareye geri döndüğünde geri sarılması gerektiği için bir çeşit sanal gevşemedir. Bunun örneği gdb'de yukarı / aşağı / bt komutları olabilir.
IMO, bu makalede verilen aşağıdaki şema , yığın çözülmesinin bir sonraki talimatın rotası üzerindeki etkisini güzelce açıklar (yakalanmamış bir istisna atıldıktan sonra yürütülecek):
Resimde:
İkinci durumda, bir istisna meydana geldiğinde, fonksiyon çağrısı yığını istisna işleyici için doğrusal olarak aranır. Arama işlevi istisna işleyici yanimain()
ile try-catch
, kapalı blokla , ancak işlev çağrısı yığınından önceki tüm girdileri kaldırmadan önce .
C ++ çalışma zamanı, fırlatma ve yakalama arasında oluşturulan tüm otomatik değişkenleri yok eder. Aşağıdaki basit örnekte f1 () atar ve main () yakalamaları, B ve A tipi nesneler arasında bu sırada yığın üzerinde oluşturulur. F1 () atıldığında, B ve A yıkıcıları çağrılır.
#include <iostream>
using namespace std;
class A
{
public:
~A() { cout << "A's dtor" << endl; }
};
class B
{
public:
~B() { cout << "B's dtor" << endl; }
};
void f1()
{
B b;
throw (100);
}
void f()
{
A a;
f1();
}
int main()
{
try
{
f();
}
catch (int num)
{
cout << "Caught exception: " << num << endl;
}
return 0;
}
Bu programın çıktısı
B's dtor
A's dtor
Bunun nedeni, f1 () attığında programın çağrı kaydının şöyle görünmesidir:
f1()
f()
main()
Böylece, f1 () patlatıldığında, otomatik değişken b yok edilir ve sonra f () patlatıldığında otomatik değişken a yok olur.
Umarım bu yardımcı olur, mutlu kodlama!
Bir istisna atıldığında ve denetim bir try bloğundan bir işleyiciye geçtiğinde, C ++ çalışma süresi try bloğunun başından bu yana oluşturulan tüm otomatik nesneler için yıkıcıları çağırır. Bu işleme yığın çözme denir. Otomatik nesneler, yapılarının tersi sırada yok edilir. (Otomatik nesneler, otomatik veya kayıt olarak bildirilen veya statik veya extern olarak bildirilmeyen yerel nesnelerdir. Otomatik x nesnesi, program x bildirildiği bloktan çıktığında silinir.)
Alt nesnelerden veya dizi öğelerinden oluşan bir nesnenin inşaatı sırasında bir istisna atılırsa, yıkıcılar yalnızca istisna oluşturulmadan önce başarıyla oluşturulan bu alt nesneler veya dizi elemanları için çağrılır. Yerel bir statik nesne için bir yıkıcı, yalnızca nesne başarılı bir şekilde oluşturulmuşsa çağrılır.
Java yığınında unwiding veya unwounding çok önemli değil (çöp toplayıcı ile). Birçok istisna işleme kağıdında bu kavramı gördüm (yığın çözme), özellikle bu yazarlar C veya C ++ 'da istisna işleme ile ilgilenir. ile try catch
blokların biz unutmak shouln't: Yerel bloklar sonra tüm nesneler arınmış yığını .