From 864e2176bb6733b2938e72e916b1ee52930883ca Mon Sep 17 00:00:00 2001 From: Angel Dimitriev Date: Sat, 30 Apr 2022 15:07:20 +0300 Subject: Update README.md --- Sem. 09/README.md | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/Sem. 09/README.md b/Sem. 09/README.md index 8b13789..53f3a32 100644 --- a/Sem. 09/README.md +++ b/Sem. 09/README.md @@ -1 +1,157 @@ + + +## Масиви от указатели към обекти. Изключения. Move семантики. +Масиви от указатели към обекти. + + ```c++ +class SomeCollection +{ + A** data; + //other things +}; + ``` +![enter image description here](https://i.ibb.co/YDCL2nr/pointer-Of-Pointers.png) +##### Какви са ползите: + + - Бързо разместване на обектите в колецкията - не се изисква да се копират. Само разместваме указателите + - Не се изисква същестуването на деф. контруктор на A. + - Възможно е да имаме "празна клетка", като се възползваме от възможната nullptr стойнот. + + +#### Изключения +![enter image description here](https://i.ibb.co/hDMRzMB/df-drawio-1.png) + + - Защо е хубаво да извикваме .close() на потоците екпслицитно ? + +#### Move сменатики + +# 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