PDA

Tam Sürümünü Görmek İçin : sizeof() ile can sıkıntısını gidermek


sckz
01/06/2005, 21:38
bugün oturup garip sınıfların sizeof ile boyutunu watch tan takip edeyim dedim..
karşılaştığım olaylardan bir kaç kafama takılan soruyu derledim :

1)
class Bos
{};

sizeof(Bos) un değeri 1 miş... Bu sınıfın içinde 1 byte kaplayan ne varki... hadi diyelim kurucu, bozucu falan var.. neyin kurucusu, bozucusu varki...

2)
class Base
{
public :
void show()
{cout << "Base";}
};

class Derived : public Base
{
public :
void show()
{cout << "Derived";}
};

int main()
{
size_t base = sizeof(Base);
size_t derived = sizeof(Derived);

return 0;
}
burda base in de derived in de değeri 1 byte. ama Base içindeki show() fonksiyonunu virtual yaptığımda her ikisinin değeri 4 oluyo..

3)
class Base
{
};

class Derived : virtual public Base
{
public :
double var;
};

int main()
{
size_t base = sizeof(Base);
size_t derived = sizeof(Derived);

return 0;
}

bunun sonucu ise base 1, derived 16... public in başındaki virtual i çıkardığımda sonuç yaklaşık olarak beklediğim gibi (yani base in 1 olması dışında).. ama virtual i koyduğumda neden sınıfın boyutu iki katına çıkıyo... -> aslında Derived sınıfı tam olarak iki katına çıkmıyo... yani Base içine int armut diye bi değişken koyduğumda, derived in değeri 24 değil (yani iki katı değil), 20 oluyo... yani sadece Derived sınıfının boyutu artıyo...

4) bu soru da günlerdir kafama takılıyo... quentin neden euler oldu ?


acehreli
01/06/2005, 22:11
1) Her nesnenin digerlerinden ayirt edilebilmesi icin ayri bir adresi olsun diye. Bos nesnelerinin buyuklugu sifir olsaydi, dizi icinde ayni yerde dururlardi.

2) Sanal islevi olan her sinif, gunumuzde kullanilan butun derleyicilerde vtbl adi verilen bir "sanal islev tablosu gostergesi" (virtual function table pointer) edinir. Nesnenin calisma zamanindaki turune gore hangi islevlerin cagrilacagina vtbl gostergesinin gosterdigi islev tablosundan bulunur.

Calistigimiz cogu ortamda siradan veri gostergeleri de 4 bayt olduklarindan, Derived'in buyuklugunun 4 olmasi normal.

Base bos oldugu halde Derived'a ayrica 1 eklenmez. Cunku artik her Derived nesnesinin kendi adresi zaten vardir. Yani bu durumda gereksizce 1 bayt ayrilmaz. (Buna "empty base class optimization" denir.)

3) Bir sinifin ogelerinin ust siniflardan gelen ogelere gore kac bayt onde veya sonda oldugu gibi hesaplar oldukca karisik olabilir. Anlasilan, sanal ust sinif durumunda bu hesaplari yapmak icin bir gostergeye (veya belki de bir "offset"e) daha ihtiyaclari oluyor.

Dusunelim: Base'den yine sanal olarak tureyen bir Derived2 sinifi olsun. Ve Derived'dan ve Derived2'den tureyen bir alt sinif:


class Base
{
int i_;

public:

Base()
:
i_(0)
{}

void degistir(int i)
{
i_ = i;
}
};

class Derived : virtual public Base
{
int j_;
};

class Derived2 : virtual public Base
{
int k_;
};

class Sonuc: public Derived, public Derived2
{};

int main()
{
Sonuc sonuc;
Base & base = sonuc;
base.degistir(42);
}


degistir islevi cagrildiginda, derleyicinin urettigi kod i_'nin bellekte nerede oturdugunu nasil bulacaktir? sonuc adli nesnenin baslangic adresinden kac bayt otededir? j_ ile k_'ye gore nerededir?

Bence o fazladan 4 bayt, bu gibi sorulari yanitlamak icin kullanilan bir tabloyu gosterir.

4) C++ standardi, dilin nasil gerceklenecegini belirlemez. Yine de Stanley Lippman'in "Inside the C++ Object Model" kitabi butun bu sorulari aciklar. (Ben okumadim.)

Ali

acehreli
01/06/2005, 22:16
Yanlis seyler yaziyorum. :/ Yukarida "fazladan 4 bayt" yerine "fazladan 16 bayt" demeliydim... Yine de ayni sey: nesne yerlerini bulmak icin hesap yapmakta kullanilan tablolar ve/veya gostergeler...

Ali

mr1yh1
02/06/2005, 03:30
tümüyle boş bir sınıfın mantıksızlığı ile ilgili ( olsa idi neler olurdu )
güzel bir açıklama da burada var..
http://www.research.att.com/~bs/bs_faq2.html#sizeof-empty
aşağıdaki kod örnek olarak verilmiş..
class Empty { };

void f()
{
Empty a, b;
if (&a == &b) cout << "impossible: report error to compiler supplier";

Empty* p1 = new Empty;
Empty* p2 = new Empty;
if (p1 == p2) cout << "impossible: report error to compiler supplier";
}

Euclides
02/06/2005, 12:28
class hello
{
char wow;
};



#pragama pack(1)
class hello
{
char wow;
};


default align de booyutu değiştirebilir...