ProgramlamaC++ Geliştirici

C++'de 'lvalue' ve 'rvalue' nedir? Aralarındaki farkları, fonksiyonlara nasıl geçtiklerini ve rvalue referanslarının (rvalue references) neden ortaya çıktığını açıklayın.

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap

C++'de lvalue (sol değer), bellekte bir nesneye işaret eden, adı olan ve referans gösterilebilen bir ifadedir (örneğin, bir değişken). rvalue (sağ değer) ise bir adı olmayan ve geleneksel anlamda bir nesne olmayan geçici bir değerdir (örneğin, a + b işleminin sonucu, 5 gibi literaller).

Lvalue adresi alınabilirken, rvalue ise alınamaz (rvalue referansları çıkmadan önce). Bunların fonksiyonlara geçişi için:

  • Normal referanslar: void foo(const std::string& s); — lvalue ve rvalue alır.
  • Lvalue referanslar: void bar(std::string& s); — sadece lvalue alır.
  • Rvalue referanslar (C++11+): void baz(std::string&& s); — sadece rvalue alır.

Örnek:

void takeValue(std::string& s) { } // lvalue void takeRValue(std::string&& s) { } // rvalue std::string s = "hello"; takeValue(s); // TAMAM, lvalue takeRValue(std::string("hi")); // TAMAM, rvalue

Rvalue referansları, geçici nesnelerin etkili bir şekilde aktarılması için gereklidir, esasen move semantiği için, kaynakları kopyalamak yerine taşımak amacıyla.

Bilmeceli Soru

std::move(obj) ifadesi hangi tür referansı (lvalue veya rvalue) alır? std::move uygulandıktan sonra, nesne hangi kategoriye dönüşür?

Cevap:

std::move(obj) her zaman rvalue referansı (T&&) döndürür, ancak nesne kendisi lvalue olarak kalır, yalnızca açık bir dönüştürme uygulanır. Bu noktada nesne ile çok dikkatli davranmak gerekir (belirsiz ama geçerli bir durumda olabilir).

Örnek:

std::string s = "data"; std::string d = std::move(s); // d, s'nin verilerini alır, s artık boştur

Bu konunun detaylarını bilmemekten kaynaklanan gerçek hatalarla ilgili örnekler.


Hikaye

Büyük bir projede, geliştiriciler geçici nesneleri lvalue referansı T& aracılığıyla geçiyorlardı (yerine T&& veya const T&). Bu, derleme hatalarına ve yetersiz kopyalamalara neden oldu — move semantiği kullanılmadı, performans %40 azaldı.


Hikaye

Frontend motorunda, std::move yanlışlıkla bir daha kullanılacak değişkenlere uygulanıyordu. Bunun sonucunda değişkenler "bozulmuş" bir durumda kalıyor, çökme ve render iş parçacıklarının çökmesine neden oluyordu.


Hikaye

Seri hale getirme kütüphanesinde, std::vector<T> türündeki bir konteyneri fonksiyona lvalue olarak geçiriyor, ancak move bekliyorlardı. Bu, taşımak yerine büyük sayıda öğenin pahalı bir şekilde kopyalanmasına yol açıyordu, bu da büyük dizilerde seri hale getirme süresini önemli ölçüde kötüleştirdi.