From 1a70a0dede8c83b3c26e09ce014e9dd20d6cf627 Mon Sep 17 00:00:00 2001 From: Angel Dimitriev Date: Wed, 12 May 2021 19:50:26 +0300 Subject: Update README.md --- Sem. 11/README.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/Sem. 11/README.md b/Sem. 11/README.md index e69de29..485b956 100644 --- a/Sem. 11/README.md +++ b/Sem. 11/README.md @@ -0,0 +1,129 @@ +# Move семантики +#### Подаване на стойност по референция +```c++ +#include +using namespace std; + +void f(int& n) +{ + cout << n << endl; +} +int main() +{ + int number = 10; + f(number); // OK! + f(3); // Error! +} + ``` +"Висящата" константа 3 **няма адрес в паметта**. За това подаването и като параметър на функцията f ще доведе до компилационна грешка. + +**&&** - за стойности без адрес в паметта +```c++ +#include +using namespace std; + +void f(int& n) +{ + cout << n << endl; +} +int main() +{ + int number = 10; + f(number); // OK! + f(3); // Error! +} + ``` + +#### Пример за използването на && +```c++ +#include +using namespace std; + +void f(int&& n) +{ + cout << n << endl; +} +int main() +{ + int number = 10; + f(number); // Error! + f(3); // OK! +} + ``` +Тук грешката възниква при подаването на променлива, която **има адрес в паметта.** +#### lvalue и rvalue + + - **lvalue** - обект, който заема някакво конкретно място в паметта. (стойността в паметта може да се модифицира) + - **rvalue** - обект, който не е *lvalue* . + + +#### Излишни копия? +Да разгледаме следният програмен фрагмент: + +```c++ +#include +#include +#include "Person.h" +using namespace std; + +Person createPerson(const char* name, int age) +{ + Person p(name, age); + + return p; +} + +int main() +{ + Person p2("Petur",18); + p2 = createPerson("Ivan", 23); +} + ``` +Тук се изпълняват следните функции на Person: + + 1. Конструктор на Person (за p2) + 2. Конструктор за Person (на p). + 3. Копиращ конструктор (за *return p*) + 4. Деструктор (в края на функцията *createPerson*) + 5. Оператор = (за *p2 = create...* ) + 6. Деструктор (в края на функцията *main*) + +Проблемът тук е, че правим излишни копия. Обектът създаден в *createPerson* **се копира два пъти докато се присвои** на p2. +#### Move конструктор и move оператор =. +За да избегнем излишните копия, може да "преместим" данните на обектът, който се създава във функцията, в данните на p2. +```c++ + +//Move constructor +Person::Person(Person&& rhs) +{ + name = rhs.name; + age = rhs.age; + + rhs.name = nullptr; +} + +//Move operator= +Person& Person::operator=(Person&& rhs) +{ + if (this != &rhs) + { + free(); + + name = rhs.name; + rhs.name = nullptr; + } + return *this; +} + ``` + + Важно е да се обърне внимание, че тук данните **не се копират**, а се **местят**. Т.е приемаме, че rhs **няма да се използва след изпълнението на функцията.** + Сега при изпълнението на първоначално разгледания код: + 1. Конструктор на Person (за p2) + 2. Конструктор за Person (на p). + 3. **Move конструктор** (за *return p*) + 4. Деструктор (в края на функцията *createPerson*) + 5. **Move oператор =** (за *p2 = create...* ) + 6. Деструктор (в края на функцията *main*) + + +Т.е тук си спестихме 2 копия за динамичната памет в Person. -- cgit v1.3.1-23-gd82d