Thread overview
The rule of five
Apr 20, 2018
hsencan
Apr 21, 2018
hsencan
Apr 21, 2018
hsencan
April 20, 2018

C++ The rule of five başlıklı bir makale okumuştum. Yazıda :

'
copy constructer
copy assignment operator,
destructor,
move constructor,
move assignment operator,'

Bunlardan birinin tanımlanması durumunda diğerlerininde tanımlanmasının şart olduğu yazıyordu. Peki bunun sebebi nedir ? Ve herhangi birini tanımlamaz isek nasıl bir sorunla karşılaşırız ?

İyi Çalışmalar.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 20, 2018

rvalue reference kavramı gelmeden önce "the rule of three" olarak bilinirdi.

Bazı türlerimiz için bunların hiçbirisini yazmak zorunda değilizdir çünkü C++ bu işlemleri otomatik olarak halleder: bütün üyeleri ilkler, sırayla kopyalar, sırayla atar[1], vs.

Eğer herhangi birisini kendimiz yazmışsak (doğrusu, "yazmak zorunda kaldıysak"), diğerlerini de ya yazmalıyızdır ya da iptal etmeliyizdir (örneğin '=delete' ile).

Örneğin, sonlandırıcı işlev içinde bir kaynağı geri verdiğimiz duruma bakalım. Örneğin sonlandırıcı içinde 'free(p)' yapıyor olalım. Eğrer kopyalayıcı işlevi kendimiz (doğru olarak) yazmazsak, p üyesinin değeri birden fazla nesne tarafından paylaşılıyor olabilir ve birden fazla nesne sonlanırken aynı p değeri ile 'free(p)' çağırır.

Ali

[1] Benim bağımsız olarak zamanında farkettiğim ve başkaları gibi "the rule of one" dediğim gibi, otomatik olarak halledilen atama işlemi hata atıldığı durumlarda doğru işlemeyebilir. Bunun nedeni, C++'ın yazdığı otomatik atama işlecinin üyelerin değerlerini sırayla değiştirmesi, ve hata atıldığı durumda o işlemleri geri çevirmemesidir. (Bir başka deyişle, C++'ın otomatik olarak yazdığı atama işleci "strongly exception safe" değildir. Bunun sonucunda, nesneler yarım atanmış durumda kalabilirler.

Otomatik yazılan diğer işleçlerde bir sorun yoktur çünkü kopyalayıcı işlerken hata atıldığında hatalı durumda bulunduğundan söz edecek nesne yoktur çünkü nesne kopyalanarak oluşturulurken hata atılmıştır ve dolayısıyla nesne oluşamamıştır.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 21, 2018

Teşekkürler Ali Hocam. Bir sorum daha var ama bu konuyla alakasız umarım yeni konu açmam gerekmiyordur.

#include <iostream>

class Base{
public:
	virtual void foo(){
		std::cout<<"Hello From Base Class"<<std::endl;
	}
};
class Derived:public Base{
public:
	void foo(){
		std::cout<<"Hello From Derived Class"<<std::endl;
	}
	void foo2(){
		std::cout<<"Derived class Function"<<std::endl;
	}
};

int main(){

	Base *base=new Base();

	Derived *derived=(Derived*)&base;

	derived->foo2();
}

Hocam burda Downcasting işleminde "Base" classtan obje türettik sonra "Derived" classına ait gösterici ile cast ettiğimiz zaman "foo2()" fonksiyonu çalışıyor. Burada "base" classnı örnekledik. Bildiğim kadarı ile "foo2()" için bellekte alan ayrılmadı ama çalıştırabildik. Bunun sebebi nedir ? Ve bu Upcasting ve Downcasting işleminde bellek farklı bir yol mu izliyor ?

İyi Çalışmalar.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 21, 2018

Aklımda hiç soru işareti kalmadı. Teşekkürler.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 21, 2018

Alıntı (hsencan):

>

bu konuyla alakasız umarım yeni konu açmam gerekmiyordur.

Gerek değil tabii ama her bağımsız konu kendi konusunda olsa çok daha iyi olur. (Yeni konu masrafı sıfır. :) )

Alıntı:

>

"Derived" classına ait gösterici ile cast ettiğimiz zaman "foo2()" fonksiyonu çalışıyor.

Sistem dili olduğundan böyle işlemlere izin verilir. Bu tür dönüşümünün doğru olduğu bütünüyle programcının sorumluluğundadır. Yani, öyle diyorsan öyledir. :) Ek bilgi olarak, C++ programcıları C tür dönüşümü işlecinden kaçınırlar çünkü o hiçbir garanti vermez. Duruma göre kısıtlama getiren ve programcıyı bazı yanlışlardan koruyan ve isteneni açıkça belirten static_cast, dynamic_cast, const_cast, ve reinterpret_cast işleçlerinden birisini yeğlerler.

Alıntı:

>

Bildiğim kadarı ile "foo2()" için bellekte alan ayrılmadı

Söylediğin, foo2 üye değişken olsaydı anlamlıdır. Yoksa üye işlevler için her nesne için zaten yer ayrılmaz. foo2 derlenir ve programın belleğinde bir yerde durur. Her foo2 çağrısı o adresteki işlemleri işletir.

Alıntı:

>

ama çalıştırabildik.

foo2 üye değişken olsaydı "erişebildik ve değerini değiştirebildik" diyebilirdir ve o zaman daha şaşırtıcı olurdu.

Alıntı:

>

Bunun sebebi nedir ?

Bu, tanımsız davranışın (undefined behavior) bir örneği. Dil, böyle bir işlemde ne olacağını tanımlamaz. Yani, örneğin "program göçer", "sigortası atar", "belleğin rasgele bir yeri kullanılır" vs. demez. Tanımsız davranışın bir sonucu, programın doğruymuş gibi çalışmasıdır. Örneğin, foo2 değişken olsaydı, nesnenin hemen yakınındaki ilgisiz baytlar kullanılırdı ve bu hata belki de senelerce hiç farkedilmeden ve hiç zarara yol açmadan gizli kalırdı. Sonra ilgisiz bir işlem daha eklendiğinde program göçebilirdi.

Alıntı:

>

Ve bu Upcasting ve Downcasting işleminde bellek farklı bir yol mu izliyor ?

Olan tek şey, derleyiciye "bana inan, bu bir Derived'dır" diyorsun ve o da sana izin veriyor. :)

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]