2016-10-18 18 views
7

vs int statik üye değişkeni bağımlı başlatma statik şekilde, gerçekte olmayan struct ii bazen 0veya başlatılır default olan 333. Bu derleme veya bağlantı sırasına göre değişir. yalancı kod göstermek için:C++ <em>statik üye değişkeni başka bir sınıf</em> olarak başlatılmış olan statik bir üye değişkeni göz önüne alındığında, yapı

class StaticClass: // file 'ONE.cpp/.hpp' 
    static int i = 2 
    static struct ii { int a = 333 } 

class ABC: // file 'abc.cpp' 
    static int abc_i = StaticClass::i // always 2 
    static struct abc_ii = StaticClass::ii // sometimes 0, sometimes 333 

(3.7 ++ clang aynı gcc 4.8.1; -Wall -Wextra şikayet hiç) i = 2/ii = 0 içinde g++ -std=c++11 abc.cpp ONE.cpp && ./a.out sonuçlar çağrı.

Ama i = 2/ii = 333yılında g++ -std=c++11 ONE.cpp abc.cpp && ./a.out sonuçları çağırarak! , Varsayılan başlatma

cat ONE.cpp abc.cpp > X.cpp && g++ X.cpp && ./a.out cat abc.cpp ONE.cpp > Y.cpp && g++ Y.cpp && ./a.out

vs Çıkarma içerir ve tek sıra halinde etrafında kodu hareketli: öyle ya da böyle dosyaları birleştirerek zaman

aynı zamanda ONE.o abc.o vs abc.o ONE.o ile olur Bu düzen varken 0 olur:

const OneI ABC::def_ii = StaticClass::ii; const OneI StaticClass::ii = OneI{333};

ve bu sipariş ile 333'e biri:

const OneI StaticClass::ii = OneI{333}; const OneI ABC::def_ii = StaticClass::ii;

Neden bu bile iki ayrı derleme birimleri ile oluyor? Bu her zaman ikincisini zorlayarak önlenebilir mi? StaticClass::ii güvenli yere ABC statik işaretçi kullanıyor (Yapmamaya olsa tercih ediyorum)?

Tam C++ kodu:


/* File: abc.cpp */ 

#include <iostream> 
#include "ONE.hpp" 

struct ABC { 
    ABC(); 

    static const int def_i; 
    static const OneI def_ii; 
    void arg_i(const int &x) { std::cout << "i = " << x << " ";}; 
    void arg_ii(const OneI &x) { std::cout << "/ ii = " << x.a << " ";}; 

}; 

ABC::ABC() { 
    arg_i(def_i); 
    arg_ii(def_ii); 
} 

const int ABC::def_i = StaticClass::i; 
const OneI ABC::def_ii = StaticClass::ii; 

int main() { 
    ABC a; 
    std::cout << '\n'; 
} 
/* End: abc.cpp */ 

/* File: ONE.cpp */ 

#include <iostream> 

#include "ONE.hpp" 

const int StaticClass::i = 2; 
const OneI StaticClass::ii = OneI{333}; 

/* End: ONE.cpp */ 

/* File: ONE.hpp */ 

#include <iostream> 

#ifndef One 
#define One 

struct OneI { 
    OneI(int a_) : a(a_) { } 
    int a; 
}; 

struct StaticClass { 
    const static int i; 
    const static OneI ii; 
}; 

#endif // One header guard 

/* End: ONE.hpp */ 

cevap

4

Tebrikler! static initialization order fiasco ile karşılaştınız.

statik nesneleri başlatma sırası

birden çok çeviri birimlerinde tanımlanmamıştır.

StaticClass::iiONE.cpp tanımlanır ve ABC::def_iiabc.cpp tanımlanmıştır. Bu nedenle StaticClass::ii veya ABC::def_ii önce başlatılır edilebilir veya edilmeyebilir. ABC::def_ii başlatılması StaticClass::ii değerini kullanır yana değeri StaticClass::ii † henüz başlatıldı bağlı olacaktır.

bir geçiş birimi tanımlanmaktadır içinde statik nesneleri başlatma sırası. Nesneler, tanımlandıkları sıraya göre başlatılır.Bu nedenle, kaynak dosyaları birleştirdiğinizde, başlatma sırası tanımlanır. Eğer yanlış sırayla dosyaları birleştirir Ancak, tanımlanmış başlatma sırası yanlıştır:

const OneI ABC::def_ii = StaticClass::ii; // StaticClass::ii wasn't initialized yet 
const OneI StaticClass::ii = OneI{333}; 

bu sonuncu sipariş her zaman uygulayarak nasılsa kaçınmak mümkün mü?

en önemsiz çözelti doğru sırayla, aynı çeviri birimi iki nesne tanımlamaktır. Daha genel bir çözüm, Construct On First Use Idiom kullanarak statik nesnelerini başlatmaktır.

güvenli StaticClass::ii için ABC statik işaretçi kullanıyor (Yapmamaya olsa tercih ediyorum)?

Sürece işaretçinin dereferenced değeri uçlu bir nesne tanımlandığı gibidir, evet bir işaretçi ile ABC::def_ii yerine güvenli olacaktır Başka bir çeviri birimi statik bir nesne başlatma sırasında kullanılmaz olarak.StaticClass::ii


sıfır-başlatılır olmuş olacak statik başlatma fazı †† sırasında. Statik başlatma sırası fiyasko, †† dinamik başlatma aşamasına ilişkindir.

†† C++ standart taslak [basic.start.static]

sabit başlatma gerçekleştirilmezse, statik depolama süresi ([basic.stc.static]) ya da iplik depolama süresi ([basic.stc olan bir değişken. iş parçacığı]) sıfır başlatıldı ([dcl.init]). Birlikte, sıfır başlatma ve sabit başlatma, statik başlatma olarak adlandırılır; diğer tüm başlatma dinamik başlatmadır. Statik başlatma, herhangi bir dinamik başlatma gerçekleşmeden önce gerçekleştirilmelidir. [Not: Yerel olmayan değişkenlerin dinamik başlatılması [basic.start.dynamic] içinde açıklanmıştır; lokal statik değişkenler [stmt.dcl] 'de açıklanmıştır. - uç not] Statik ve dinamik başlatma fazları ve ne kadar dinamik başlatma gerekli düzeni kurmak üzerinde durmak isteyebileceğiniz

+0

. Aksi halde cevabınız, bir hikayenin yarısından daha azdır. –

+0

@MaximEgorushkin Statik ve dinamik başlatma hakkında ayrıntı ekledim. Başlatılmamış StaticClass :: ii' değerinin neden 0 olması gerektiğini anlamamıza yardımcı olurken, bu sorunun önemine katılmıyorum. – user2079303

+0

Sipariş a) sıfır başlatma, b) statik başlatma, c) dinamik başlatma? Ve 'const int StaticClass :: i = 2' b olduğundan,' const int ABC :: def_i = StaticClass :: i' nedir? Dinamik sanırım. – toting

İlgili konular