Thread overview
move semantics
Mar 11, 2018
hsencan
Mar 11, 2018
kerdemdemir
Mar 11, 2018
hsencan
March 11, 2018

Herkese iyi akşamlar,

Ben 2 gündür bu 'move semantics''in ne olduğunu kavramaya çalışıyorum. :) Ama henüz başaramadım.
Rvalue ne olduğunu anladım. Fakat move semantics de takıldım. Birde buraya danışayım dedim.

Şimdiden Teşekkür Ederim.

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

March 11, 2018

Merhaba,

Soruların bence çok güzel. Umarım güzel projelerde bunları kullanma şansın olur.

Ben açıklamayı Ali Abi'ye bırakıp örnek veriyorum. Onun açıklama daha iyi ve doğru olacaktır.

class A
{
	void foo()
	{
		 std::vector<double> gecici( 100000 );
		 //Diyelim bir şeyler yaptık gecici ile ve isimiz bitti
        //kalici = gecici; //Burda Copy Ctor cagrilir ve "deep copy" yapilir
        // bir sürü "allocation", kopyalama masrafi olur
        kalici = std::move(gecici); // Burda Move Ctor cağrilir   "shallow copy" yapilir. Çok az
        //masrafli olur.


	}
        std::vector <double>  kalici;
}

RValuelarda benim bildiğim kadarıyla:

fonksiyon dönüş değerleri, sabit değerler( int a = 5; deki "5" gibi) geçici değerler.

Bu geçici değerlerin C++11 'den önce direk bir değişkene atanamamaları çok kopyalama masrafına neden oluyordu. Gereksiz kopyalamaların önüne geçebilmek için bu daha öncedende olan rvalue 'ları && ile değişken olarak alabilmemizi sağladılar. Ve "move constructor" diye yeni bir constructor çıkardılar. Ve bütün standart container'lar(vector, map, list vs..) bu move ctor'ü eklediler. Move ctor "deep copy" yerine "shallow copy" yapıyor.
Geçici değişkenlerin datalarının üstüne konuyoruz kopyalamak yerine.

Erdemdem

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

March 11, 2018

Soruların bence çok güzel. Umarım güzel projelerde bunları kullanma şansın olur.

Sorduğum tüm sorulara uzun uzun detaylı ve anlaşılacak biçimde cevap yazdığınız için hem Ali hocama Hem de size çok teşekkür ediyorum. (Bazen diyorum keşke forumu daha önce keşfetseydim diye :) ) Dediğiniz gibi umarım ileride burada öğrendiklerim ile büyük projeler geliştirecek kadar iyi olurum.

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

March 11, 2018

Bu konuda konuşacak çok şey var. O yüzden, hızlıca özetlemeye çalışacağım. :)

C'de olduğu gibi, C++'ta da bütün türler değer türleridir (value type); işlevlere parametre olarak geçirildiklerinde ve işlevlerden döndürüldüklerinde kopyalanırlar. (Dizilerin "ilk elemanlarına gösterge"ye dönüşme gibi özel bir kuralları vardır ama o istisna...)

KUllanıcı türlerinin doğru kullanılabilmeleri için kopyalayıcı işlevlerden (copy constructor) yararlanılır. Böylece nesneler kendi üyelerini diledikleri gibi değiştirebilirler. (Öyle olmasaydı birinde yapılan değişiklik diğerini de etkilerdi. (Bazı durumlarda istenen tam da budur; ama o ayrı konu.))

Kopyalama işlemi gereksiz masraftan kaçınma ilkesini güden C++ için bir sorundur çünkü bazı durumlarda kopya gereksizdir. Örneğin, bir işlev bir sağ değer ile çağrıldığında sağ değerin kopyalanmasına gerek yoktur çünkü tanım gereği, o sağ tarafın çağıran tarafta tekrar kullanılması zaten olanaksızdır. Yani, bar sağ döndürüyorsa, 'foo(bar())' dendiğinde o sağ değerin tekrar foo'ya parametre değeri olarak kopyalanması gereksiz bir masraftır. Bunun en tanıdık örneğin, bir vector'e bir eleman eklendiği durumdur: 'noktalarim.push_back(Nokta(1, 2))'. Oluşturulan sağ değer vector'ün kendi bellek alanına kopyalanır.

Aynı biçimde, işlevlerin dönüş değerleri de gereksizce çağıran tarafa kopyalanabilir. (Derleyiciler bu durumda RVO (return value optimization) ve NRVO (named return value optimization) denen yöntemleri kullanabilirler ama her durumda değil.)

C++ dünyası bu sıkıntılı duruma hep çare aramıştır. Bu çabalardan birisi, D'nin iki numaralı adamı Andrei'ye aittir: http://www.drdobbs.com/move-constructors/184403855

C++ sonuçta sağ değer referansı (rvalue reference) denen çözümde karar kılmıştır. (C++ olanaklarının ne anlama geldiklerini ve kullanımlarını açıklamakla ünlü Scott Meyers bu terimin yanlış olduğunu ve daha doğru terimin "universal reference" olması gerektiğini savunmuştur.)

Move constructor, kaynak nesnenin iç organlarını masrafsızca hedefe aktaran işlevdir. Örneğin, tek p gösterge üyesi olan bir tür, 'hedef->p = kaynak->p; kaynak->p = nullptr;' işlemlerinden sonra kaynak'ı hedef'e aktarmış olur. (Yalnızca iki gösterge kopyalayarak, masrafsızca.)

Referans türü kullanan Java gibi dillerin böyle bir sorunu yoktur çünkü işlev çağrılarında kopyalanan nesne değil, referanstır (yani, gösterge).

Hem referans hem değer türü kullanan D'de ise bu iş dil tarafından halledilmiştir: sağ değerler zaten otomatik olarak aktarılırlar. Ben bu konuda bir konuşma yapmıştım: https://www.youtube.com/watch?v=mPr2UspS0fE

Ali

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