2010-10-27 17 views
9

Kurucu başlatma listesinde yürütme sırası belirlenebilir mi? Bir sınıfa üyeleri sırası bu üyeler başlatılır sırası olduğunu biliyoruz ama böyle bir senaryo varsa: Bunun Yapıcı başlatma listesindeki yürütme sırası

class X() 
{ 
X_Implementation* impl_; 
}; 

and then providing that allocator is available: 

X::X():impl_(Allocate(sizeof(X_Implementation)))//HERE I'M ALLOCATING <--1 
,impl_(Construct<X_Implementation>(impl_))//AND HERE I'M CONSTRUCTING <--2 
{ 
} 

ama sırayla

bu düzen soldan sağa doğru GEREKIR güvenilir olmak. GREAT BOOK OF std :: tarafından garanti edilmiyor mu, değil mi? Eğer değilse, her zaman ikinci çizgiyi vücuda taşıyabilirim.

+1

Daha önce ayırdığınız bir bellek arabelleği oluşturmak için yeni yerleşimi kullanın. –

+0

Bir nesneyi birden çok kez başlatamazsınız, bu nedenle bu soru bir dizisizdir. Bunun ötesinde, [Oluşturucu başlatma listesi değerlendirme sırası] 'nın açık bir kopyası (https://stackoverflow.com/questions/1242830/constructor-initialization-list-evaluation-order) –

cevap

28

14882: 2003 (E) bölüm 12.6.2:

Başlatma şu sırayla devam eder

:

  • Birinci ve sadece aşağıda açıklandığı gibi en türetilmiş sınıfın kurucusu için, sanal taban sınıfları, , temel sınıfların yönelimli asiklik grafiğinin bir derinlik-ilk soldan sağa geçişinde göründükleri sırayla başlatılacaktır; soldan sağa ” türetilmiş sınıf temel belirleyici listesindeki temel sınıf adlarının görünüş sırası.Daha sonra, doğrudan temel sınıflar, (belirteçleri sıfırlayanların sırasına bakılmaksızın) temel belirteçleri listesinde görüldükleri için beyanname sırasına göre başlatılacaktır. Daha sonra, statik olmayan veri elemanları, sınıf tanımında bildirildikleri sırayla başlatılacaktır (yeniden başlatıcıların sırasına bakılmaksızın). Son olarak yapıcının gövdesi yürütülür.

Yani, bu emri takip ve sipariş gerekecek. Ayrıca standarda göre, sipariş, nesnelerin tam tersi sırada başlatılmayacak şekilde reçete edilir.

22

C++ standart başlatma listeleri için bir emir (ISO C++ Standart 12.6.2/5) garanti yapar:

... nonstatic veri üyeleri onlar ilan edildi sırayla başlatıldı edilecektir sınıf tanımı (yine mem başlatıcılarının sırasına bakılmaksızın).

(Daha fazla bilgi için Wyatt Anderson's answer bakınız.)

Örnek:

class Foo 
{ 
public: 
    Foo(); 
private: 
    A a; 
    B b; 
    C c; 
}; 

Foo::Foo() : b(), a(), c() 
{ 
    // a is initialized first, then b, then c - NOT b, a, then c! 
} 

Ancak, iki kez, bir değişkene başlangıç ​​olamaz - Eğer derleme olmaz bağlar var.

X::X() : impl_(Allocate(sizeof(X_Implementation))) 
{ 
    impl_ = Construct<X_Implementation>(impl_); 
} 

yukarıdaki kod ile, ama aslında ben ne Allocate() veya Construct() bilmeden istisna güvenlik sorunları olabilir':

class X //() what's with the pair of parentheses you have in your code snippet? 
{ 
public: 
    X(); 
private: 
    X_Implementation* impl_; 
}; 

X::X() : 
    impl_(Allocate(sizeof(X_Implementation))), 
    // It is not allowed to initialize a data member twice! 
    impl_(Construct<X_Implementation>(impl_)) 
{ 
} 

Bunun yerine, sadece yapıcı içine fazladan iş koymak söyleyemiyorum. Ben bunu yaparsanız bunun kendi sınıflara ayırma ve ayrı ayrı yapılması en iyisi olduğunu söyleyebilirim, o deyim Kaynak Edinme Is Başlatma (RAII) kullanılarak:

class XBase 
{ 
protected: 
    XBase() : impl_(Allocate(sizeof(X_Implementation))) 
    { 
    } 

    ~XBase() 
    { 
     if(impl_ != 0) { Deallocate(impl_); } // Or something like this 
    } 

    X_Implementation* impl_; 
}; 

class X : private XBase // XBase is an implementation detail 
{ 
public: 
    X() 
    { 
     impl_ = Construct<X_Implementation>(impl_); 
    } 

    ~X() 
    { 
     Destruct<X_Implementation>(impl_); // Or something like this 
    } 
}; 

Bu şekilde, Construct() bir istisna atar,, Temel sınıf yıkıcısı çağrılacağından hafızayı kaçırmayacaksınız, bu da impl_ ile işaretlenmiş belleği kaldıracaktır. Bu önemlidir, çünkü istisna yakalanmaz ve kurucudan ayrılırsa, eşleştiricisi , olarak adlandırılamaz. İstisna güvenliği konusunda Bjarne Stroustrup'un kağıdı bakınız: ISO/IEC göre http://www2.research.att.com/~bs/except.pdf

4

Özel senaryonuz, aynı üyeyi bir kereden fazla başlatma fikri üzerine kurulmuştur. Bu C++ 'da düzensiz. Kodunuz derlenmeyecek. Yani, sorduğunuz soru gerçekten mevcut değil.

Üye başlatma sırası, sınıf tanımındaki beyanlarının sırasıdır. Yapılandırma başlatıcı listesindeki başlatma sırasına ilişkin her şeyi kapsayan kalıtım dışı bağlamlarda.