C ++ işlevindeki statik değişkenin ömrü nedir?


373

Bir değişken staticbir işlevin kapsamında olduğu bildirilirse, yalnızca bir kez başlatılır ve işlev çağrıları arasındaki değerini korur. Ömrü tam olarak nedir? Yapıcısı ve yıkıcısı ne zaman çağrılır?

void foo() 
{ 
    static string plonk = "When will I die?";
}

Yanıtlar:


257

Fonksiyonu süresi staticdeğişkenleri ilk kez başlar [0] program akış beyanı karşılaşır ve program sona sona erer. Bu, çalışma zamanının, yalnızca gerçekten inşa edilmişse, onu yok etmek için bir miktar kitap tutma gerçekleştirmesi gerektiği anlamına gelir.

Ek olarak, standart statik nesnelerin yıkıcılarının yapılarının tamamlanmasının tersi sırada çalışması gerektiğini söylediğinden [1] ve yapım sırası belirli program çalışmasına bağlı olabilir, yapım sırası dikkate alınmalıdır .

Misal

struct emitter {
    string str;
    emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
    ~emitter() { cout << "Destroyed " << str << endl; }
};

void foo(bool skip_first) 
{
    if (!skip_first)
        static emitter a("in if");
    static emitter b("in foo");
}

int main(int argc, char*[])
{
    foo(argc != 2);
    if (argc == 3)
        foo(false);
}

Çıktı:

C:> Örnek.exe
foo içinde düzenlendi
foo perişanım

C:> Örnek.exe 1
eğer düzenlendi
foo içinde düzenlendi
foo perişanım
eğer perişanım

C:> sample.exe 1 2
Oluşturuldu foo
oluşturulan Eğer yok
edildi Eğer
foo yok edildi

[0]Yana C ++ 98 [2] Bu çok dişli bir ortamda davranır olacak kadar çok parçacığı için bir referans vardır belirtilmemiş, ve sorunlu olabilir Roddy bahseder.

[1] C ++ 98 bölümü 3.6.3.1 [basic.start.term]

[2]C ++ 11'de statik bir iş parçacığı güvenli bir şekilde başlatılır, bu Sihirli İstatistikler olarak da bilinir .


2
C'tor / d'tor yan etkisi olmayan basit tipler için, bunları küresel basit tiplerle aynı şekilde başlatmak basit bir optimizasyondur. Bu dallanmayı, bayrağı ve yıkım sırası sorunlarını önler. Bu, ömürlerinin farklı olduğu anlamına gelmez.
John McFarlane

1
İşlev birden çok iş parçacığı tarafından çağrılabiliyorsa, bu statik bildirimlerin C ++ 98'de bir muteks tarafından korunması gerektiğinden emin olmanız gerektiği anlamına mı geliyor?
allyourcode

1
"küresel nesnelerin yıkıcıları", inşaatlarının tamamlanmasının tersi sırada çalıştırılmalıdır "burada geçerli değildir, çünkü bu nesneler küresel değildir. Statik veya iplik saklama süresi olan yerlilerin imha sırası saf LIFO'dan çok daha karmaşıktır, bkz. Bölüm 3.6.3[basic.start.term]
Ben Voigt

2
"Program sona erdiğinde" ifadesi kesinlikle doğru değil. Dinamik olarak yüklenen ve kaldırılan Windows dll'lerindeki statik durumlara ne dersiniz? Açıkçası C ++ standardı meclislerle hiç ilgilenmiyor (eğer yapsaydı güzel olurdu), ancak standardın burada söylediği şey hakkında bir açıklama iyi olurdu. "Program sonlandırmada" ifadesi dahil edilirse, teknik olarak C ++ 'ın dinamik olarak yüksüz derlemelerle uyumsuz olarak herhangi bir uygulamasını yapacaktır.
Roger Sanders

2
@Motti Standardın dinamik kütüphanelere açıkça izin verdiğine inanmıyorum, ancak şimdiye kadar standartta özellikle uygulanmasıyla çelişen bir şey olduğuna inanmadım. Tabii ki, buradaki dili kesinlikle söylemek gerekirse, statik nesneler daha önce başka yollarla yok edilemez, sadece anadan dönerken veya std :: exit çağrılırken yok edilmesi gerekir. Bence oldukça ince bir çizgi.
Roger Sanders

125

Motti sipariş hakkında doğru, ancak dikkate alınması gereken başka şeyler var:

Derleyiciler genellikle yerel statiklerin zaten başlatılıp başlatılmadığını göstermek için gizli bir bayrak değişkeni kullanır ve bu bayrak işleve her girişte işaretlenir. Açıkçası bu küçük bir performans isabeti, ancak daha da endişe verici olan, bu bayrağın iş parçacığı için güvenli olduğu garanti edilmemesidir.

Yukarıdaki gibi bir yerel statikiniz varsa ve foobirden çok iş parçacığından çağrılırsanız, plonkyanlış veya hatta birden çok kez başlatılmasına neden olan yarış koşullarınız olabilir . Ayrıca, bu durumda plonk, onu oluşturandan farklı bir iplikle tahrip olabilir.

Standardın söylediklerine rağmen, yerel statik yıkımın gerçek sırasına çok dikkat ederim, çünkü farkında olmadan hala yıkılmasından sonra hala geçerli olan bir statik varlığa güvenebilirsiniz ve bu izini bulmak gerçekten zordur.


68
C ++ 0x statik başlatmanın iş parçacığı için güvenli olmasını gerektirir. Bu yüzden dikkatli olun, ancak işler sadece daha iyi olacak.
deft_code

İmha emri sorunları küçük bir politika ile önlenebilir. statik / genel nesneler (tektonlar, vb.) yöntem gövdelerindeki diğer statik nesnelere erişemez. Yalnızca bir referansın / işaretçinin yöntemlerde daha sonra erişim için saklanabileceği kurucularda erişilebilir. Bu mükemmel değil, ancak vakaların 99'unu düzeltmeli ve yakalamadığı durumlar açıkça balık ve bir kod incelemesine takılmalıdır. Politika dilde uygulanamadığı için bu hala mükemmel bir düzeltme değildir
deft_code

Biraz çaylağım ama neden bu politika dilde uygulanamıyor?
cjcurrie

9
C ++ 11'den beri, bu artık bir sorun değil. Motti'nin cevabı buna göre güncellenir.
Nilanjan Basu

10

Mevcut açıklamalar, 6.7'de bulunan Standardın gerçek kuralı olmadan tam olarak tamamlanmamıştır:

Statik depolama süresi veya iş parçacığı depolama süresi olan tüm blok kapsamı değişkenlerinin sıfır başlatılması, başka bir başlatma yapılmadan önce gerçekleştirilir. Varsa, statik depolama süresine sahip bir blok kapsamı varlığının sürekli başlatılması, bloğu ilk girilmeden önce gerçekleştirilir. Bir uygulamanın, ad alanı kapsamındaki statik veya iş parçacığı depolama süresine sahip bir değişkeni statik olarak başlatmasına izin verilen koşullar altında, statik veya iş parçacığı depolama süresine sahip diğer blok kapsamı değişkenlerinin erken başlatılmasına izin verilir. Aksi takdirde, böyle bir değişken kontrolün bildiriminden ilk kez geçtiğinde başlatılır; böyle bir değişken, başlatılmasının tamamlanmasının ardından başlatılmış sayılır. Başlatma bir istisna atarak çıkarsa, başlatma tamamlanmamıştır, bu nedenle kontrol bir sonraki deklarasyona girdiğinde tekrar denenecektir. Değişken başlatılırken kontrol bildirime eşzamanlı olarak girerse, eşzamanlı yürütme başlatmanın tamamlanmasını beklemelidir. Değişken başlatılırken denetim bildirime yinelemeli olarak tekrar girerse, davranış tanımsız olur.


8

FWIW, Codegear C ++ Builder standardına göre beklenen sırada yok olmaz.

C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if

... bu yıkım düzenine güvenmemenin bir başka nedeni!


57
İyi bir argüman değil. Bu derleyiciyi kullanmamanın bir argüman olduğunu söyleyebilirim.
Martin York

26
Hmm. Teorik olarak taşınabilir koddan ziyade gerçek dünya taşınabilir kodu üretmekle ilgileniyorsanız, dilin hangi alanlarının sorunlara neden olabileceğini bilmek yararlı olduğunu düşünüyorum. C ++ Builder bunu ele alma konusunda benzersiz olsaydı şaşırırdım.
Roddy

17
Ben kabul ediyorum, ancak "hangi derleyiciler sorunlara neden ve dilin hangi alanlarda yaparlar" olarak ifade ediyorum;
Steve Jessop

0

Statik değişkenler kez devreye giriyor edilir programı yürütülmeye başlanmasından ve programın çalışması biter kadar kullanılabilir durumda kalır.

Statik değişkenler Belleğin Veri Segmentinde oluşturulur .


Bu işlev kapsamındaki değişkenler için geçerli değildir
awerries
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.