| Name | Size | |
|---|---|---|
| .. | ||
| MyString (with move) | 78 B | log stats plain |
| README.md | 4.7 KiB | log stats plain blame |
| StringPool | 155 B | log stats plain |
Масиви от указатели към обекти. Изключения. Move семантики.
Масиви от указатели към обекти.
c++
class SomeCollection
{
A** data;
//other things
};

Какви са ползите:
- Бързо разместване на обектите в колецкията - не се изисква да се копират. Само разместваме указателите
- Не се изисква същестуването на деф. контруктор на A.
- Възможно е да имаме "празна клетка", като се възползваме от възможната nullptr стойнот.
Изключения

- Защо е хубаво да извикваме .close() на потоците екпслицитно ?
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:
- Конструктор на Person (за p2)
- Конструктор за Person (на p).
- Копиращ конструктор (за return p)
- Деструктор (в края на функцията createPerson)
- Оператор = (за p2 = create... )
- Деструктор (в края на функцията 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.
