PDA

Tam Sürümünü Görmek İçin : constructor


quasimodo
10/05/2007, 15:09
class Array {
public:
Array( int = 10 ); // varsayilan constructor
Array( const Array & ); // kopya constructor
~Array(); // yıkıcı

private:
int size; // arrayin uzunlugu
int *ptr; // array ilk elemaninin baslangic adresi
};

Array::Array( int arraySize )
{
size = ( arraySize > 0 ? arraySize : 10 );
ptr = new int[ size ]; // array icin bos alan ayriliyor
assert( ptr != 0 ); // ayrilamazsa sonlandir

for ( int i = 0; i < size; i++ )
ptr[ i ] = 0; // array initialize ediliyor
}

Array::Array( const Array &init ) : size( init.size )
{
ptr = new int[ size ]; // array icin bos alan ayriliyor
assert( ptr != 0 ); // ayrilamazsa sonlandir

for ( int i = 0; i < size; i++ )
ptr[ i ] = init.ptr[ i ]; // kopyalaniyor
}

// Destructor
Array::~Array()
{
delete [] ptr;
}

class imizdan bir nesne olustururken ve buna yapici ile ilk
deger verirken normalde
Array numbers(7);
yapiyorduk ya.

Array numbers = 7;
Bunu bu sekilde yapabilirmiyiz?
Bunu bu sekilde yaptigimizda yine yapici fonksiyon cagirilirmi?
Bunu yapabilmek icin = operatorunu asiri yuklemelimiyiz?


lektroon
10/05/2007, 15:43
Evet yapabilirsin.
Array numbers = 7;

dediginde compiler Array(int = 10) constructor'ini cagirir. Yani implicit type conversion yapar. Ancak eger sen bunun bu sekilde yapilamamasini saglamak istiyorsan, constructor'in onune explicit keyword'unu eklemelisin.

explicit Array(int = 10);

O zaman:
Array numbers = 7; //Invalid
Array numbers(7); //Valid

olur.

acehreli
10/05/2007, 20:09
1) assert( ptr != 0 ); satirinda ptr hicbir zaman 0 olamaz, cunku new'un bellek ayiramamasi durumunda std::bad_alloc hatasi atilir ve o satira zaten gelinemez. (new malloc degildir! :) )

2) Ayrica, assert programcinin kendi kendisini denetlemek icin kullandigi bir aractir. Bellek ayiramamak boyle bir hata olmadigi icin assert uygun degil. Ama hic yoktan iyidir. :)

3) Uc islevler kuralini unutmussun cunku Array'in atama isleci (operator=) tanimlanmamis! Bu kurala gore, eger su uc islevden herhangi birisini yazmissan, hemen hemen her zaman ucunu de en azindan bildirmen gerekir: kopyalayici, atama isleci, ve bozucu islev.

4) lektroon explicit'i zaten anlatmis.

Ek olarak; ben olsam explicit yapardim, cunku int istenen yerlere yanlislikla Array gonderildiginde derleyicinin sessizce kabul etmesi herhalde uygun olmazdi. Cunku soyle bir kullanimda da calisirdi:


void foo(const Array & dizi);

int main()
{

// yanlislik mi, yoksa gercekten uzunlugu 5 olan bir dizi mi istedim?
foo(5);
}


Array kurucusu explicit olursa foo(5) satiri calismaz. Eger gercekten Array istiyorsam bunu acikca ("explicitly") soylemem gerekir:

foo(Array(5)); // cok daha guzel ve "acik"! :)

Ali

quasimodo
11/05/2007, 14:50
Aslinda new de boyle bir denetimin yanlis oldugunu biliyorum
ama hata yakalama konusunu ogrenene kadar sanirim
bu sekilde kullanicam.

Array numbers = 7;
Bu sekilde cagirilmasini kurucu fonksiyonu
private yaparak engelleyebilirmiyim?

Yoksa kurucu fonksiyonu private yaptigim zaman
sadece
Array numbers = Array(5);
sekilde yapılmasi mi engellenmis olur???

acehreli
11/05/2007, 21:03
1) Hata yakalama ile ilgili cok temel bir seyi ogrendigin zaman, o assert'teki ptr'in hicbir zaman 0 olmayacagini anlayacaksin. Yani o assert satirini yazmanin bir anlami yok, cunku o satir her zaman dogru calisacak.

Hata yakalama ile ilgili cok temel bir seyi ogrenecegin zaman iste bu zaman: :) new sirasinda hata atilirsa, o hatanin atildigi noktadan sonra hicbir islem isletilmez. Her bir kod kapsami teker teker terk edilir ve atilan hatanin turune uygun bir catch aranir.

Ozetle:

ptr = new int[ size ]; // eger burada hata atilirsa,
assert( ptr != 0 ); // bu satir isletilmez bile

Programin akisi o iki satiri kapsayan blogun disina cikar. (O bloktaki otomatik nesneler sonlandirildiktan sonra.)

Hata atma konusunda yeterli bilgiyi aldin; onun icin oradaki assert'in hicbir ise yaramadigini goruyorsun. :)

Bu arada, new iki nedenle hata atabilir:

- kendisi bellek ayiramazsa std::bad_alloc atilir,
- kurmakta oldugu nesnenin kurucusu hata atarsa, o hata atilir.

Eger assert satirini kullanmakta israrliysan, yani new'un malloc gibi davranmasini istiyorsan, o zaman o sekilde davranan new'u acikca kullanman gerekiyor:


ptr = new (nothrow) int[ size ]; // artik hata atmaz, bellek bulamazsa 0 dOndUrur
assert( ptr != 0 ); // bu satir isletilir

Ama nothrow ancak new'un bellek ayiramadiginda attigi hatayi durdurur. Kurdugu nesnenin kurucusunun attigi hatalar yine bu kapsamdan hemen cikilmasina neden olur.

2) Kurucuyu private yaparsan, o nesneyi yalnizca o sinifin bir islevi veya o sinifin friend'leri kurabilir. Degisen bir sey yok yani. private, yalnizca erisimi belirler.

Array numbers = Array(5);

kullaniminin engellenmesini explicit anahtar sozcuguyle ilgili olarak konusmustuk... (C++'in karisik oldugunu soylemistik degil mi. :D)

Ali