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. ]