Move Semantics

Move Semantics

Bir objeden başka bir objeye kaynakların verimli bir şekilde aktarılmasını sağlar. Örneğin garajınızda bir arabanız var. Anahtarını arkadaşınıza verip “artık bu senin” diyorsunuz. Artık bir arabanız yok ve arabayı tekrardan kullanmak için arkadaşınızın anahtarı geri vermesi gerekli. Arabayı arkadaşınıza vermek için bir kopya oluşturmadınız onun yerine var olanı transfer ettiniz.

Value Semantics

Verileri transfer etmek için kopyalarsınız. Bu durum sizi bir garbage collector kullanmaktan kurtarır lakin verimi daha düşüktür. Bir fonksiyona bir argüman verdiğinizde default olarak kopyalama işlemi yapar.

Move işleminde eğer değişkeniniz rvalue ise kopyalanmak yerine transfer/move edilebilir.

Lvalues and Rvalues

Bir obje, lvalue veya rvalue olabilir. Klasik olarak bir lvalue atama operatörünün solunda ve bir rvalue atama operatörünün sağında bulunabilir.

x = 5;     // x lvalue; 5 rvalue
y = f();   // y lvalue; f()'in dönüş değeri rvalue

Tabi bu tanım yeterince açık değil. C++’da lvalue, isimlendirilmiş bir bellek bölgesini ifade eder.

  • İsmi olmalı
  • & operatörü ile adresini alabilmeliyiz

Bunun dışında kalan her şey rvalue’dür yani:

  • & ile adresi alınamaz

Fonksiyonlara atanırken farklı davranışlar gösterebilir. Bir lvalue

MethodLvalueRvalue
Pass by valuef(x) f(5)
Pass by adress (pointer)f(&x) Yapamaz
Pass by referencef(x)Yapamaz
Pass by const referencef(x)f(5)
  • Pass by value’de değerler kopyalanıp öyle atanıyor dolayısıyla her ikisi için de sorun yok.
  • Pass by adress’de ise belli bir bellek bölgesinin adresini göstermemiz gerekli Rvalue ile böyle bir şey yapamıyoruz
  • Pass by reference’de de aynı durum geçerli.
  • Pass by const reference’de ise bunun aksine Rvalue ile atama yapmak mümkün. Çünkü const olması bu değişkenin fonksiyon içinde değişmeyeceğini garanti eder. Bu sayede 5 sayısını fonksiyon içinde kullanabiliriz.

Pass by move

Lvalue and Rvalue References

Lvalue Reference

  • Arka planda pointer olarak implemente edilebilir. [1]
  • lvalue ‘ları referans edebilir
  • const olduğunda rvalue ‘leri de referans edebilir.
	int a = 5;   // a is a lvalue
	int& ra = a; // ra is a lvalue reference
	int& rb = 5; // ERROR: A rvalue cannot bind to lvalue reference ...
	const int& rc = 5; // ... unless it is const

Rvalue Reference

  • Rvalue tutmak için rvalue reference kullanabiliriz.
  • Rvalue reference, bir lvalue’dür !
	int&& a = 5;
	cout << a << endl;  // 5
	cout << &a << endl; // 0000007899CFFCB0
	// 5 is a rvalue, a is a lvalue !!!
	// even it is reference a rvalue 
	
	
	int lv = 5;
	int&& b = lv; // ERROR: an rvalue reference cannot be bound to an lvalue
	
  int&& b = std::move(lv); // but we can use std::move 
	cout << &b << endl;  // 5
	cout << &lv << endl; // 5

std::move()

  • gerçekte move etmez, rvalue’e cast eder.
  • rvalue alan yerlere lvalue atmak için kullanılır
  • lvalue’nun gözden çıkarılabilir olması gerekli çünkü tuttuğu data std::move() çalıştıktan sonra kullanılabilir olmayabilir.
MethodLvalueRvalue
Pass by valuef(x) f(5)
Pass by adress (pointer)f(&x) Yapamaz
Pass by lvalue referencef(x)Yapamaz
Pass by const lvalue referencef(x)f(5)
Pass by rvalue referenceYapamazf(5)

Value Categories

  • Literals
    • ismi yoktur ve referans edilemezler
    • pure rvalues veya prvalues olarak isimlendirilir
  • Temporary objects
    • Data’sı move edilebilir bir objeyi temsil eder
    • xvalues olarak adlandırılır.
  • lvalues

https://learn.microsoft.com/en-us/cpp/cpp/lvalues-and-rvalues-visual-cpp?view=msvc-170

https://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues

Move Operators

#include <iostream>
#include <string>

using namespace std;

class Text{
public:
	// Constructors 
	Text();							// Default constructor
	Text(const Text& other);		// Copy constructor
	Text(Text&& other) noexcept;	// Move constructor
	~Text();						// Destructor

	// Assignment operators 
	Text& operator=(const Text& other);			// Copy assignment 
	Text& operator=(Text&& other) noexcept;		// Move assignment 

private:
	int size;
	char* data;	
};


// Default constructor
Text::Text() : size{}, data{} {}

// Copy constructor
Text::Text(const Text& other) : size(other.size), data(new char[other.size]){
	std::copy(other.data, other.data + size, data);
}

// Move constructor
Text::Text(Text&& other) noexcept : size{}, data{}{
	size = other.size;
	data = other.data;
	
	other.size = 0;
	other.data = nullptr;
}

// Destructor
Text::~Text(){
	delete[] data;
}

// Copy assignment 
Text& Text::operator=(const Text& other){
	if (this != &other) {
		delete[] data;

		size = other.size;
		data = new char[size];
		std::copy(other.data, other.data + size, data);
	}
	return *this;
}

// Move assignment 
Text& Text::operator=(Text&& other) noexcept{
	if (this != &other) {
		delete[] data;

		size = other.size;
		data = other.data;

		other.size = 0;
		other.data = nullptr;
	}
	return *this;
}

https://learn.microsoft.com/en-us/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=msvc-170

  • move only
  • copy only
  • reference collapsing
  • forwarding

Perfect Forwarding

https://stackoverflow.com/questions/13725747/what-are-the-reference-collapsing-rules-and-how-are-they-utilized-by-the-c-st

Kaynaklar

  1. https://stackoverflow.com/questions/3954764/how-are-references-implemented-internally


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *