С++11 ввел семантику перемещения, которая при наличии rvalue значения, позволяет его перемещать явно или не явно. Не явно это происходит, при оптимизации во время компиляции. Явно перемещение можно задать с помощью std::move(obj), для объектов которые поддерживают перемещение в своих типах. Поддержку перемещения можно обеспечить, явно определив конструктор перемещения и перемещающий оператор присваивания. Таким образом правило трех превратилось в правило пяти. Если мы хотим запретить копирование, то можем указать запрет на автоматическое создание с помощью =delete для конструктора копирования и копирующего оператора присваивания.
#include <iostream>
class Box {
public:
//constructor
explicit Box(int _number) : number{_number} {
bigData = new int(number);
}
//destructor
~Box() {
delete bigData;
}
//copy constructor
Box(const Box &other) {
number = other.number;
bigData = new int(0);
*bigData = *other.bigData;
}
//copy assign operator
Box &operator=(const Box &other) {
if (this == &other)
return *this;
number = other.number;
delete bigData;
bigData = new int(0);
*bigData = *other.bigData;
return *this;
}
//move constructor
Box(Box &&other) noexcept {
number = other.number;
bigData = other.bigData;
other.number = 0;
other.bigData = nullptr;
}
//move assign operator
Box &operator=(Box &&other) noexcept {
if (this == &other)
return *this;
number = other.number;
delete bigData;
bigData = other.bigData;
other.number = 0;
other.bigData = nullptr;
return *this;
}
public:
int *bigData = nullptr;
int number;
};
Стандартная библиотека си++ предлагает специальные типы для решения задачи владения, так называемые умные (smart) указатели. Рассмотрим основные из них, это уникальный указатель std::unique_ptr<T> и указатель совместного владения std::shared_ptr<T>. При их использовании нет необходимости в new и delete. Также умные указатели возвращают bool при проверках. В отличие от сырых (raw) указателей, умные указатели отвечают за очистку памяти при их удалении.
int main() {
Box box{10}; // constructor
Box box1{box}; // copy constructor
Box box2 = box1; // copy assign operator
Box box3{std::move(box2)}; // move constructor
Box box4 = std::move(box3); // move assign operator
std::cout << (box3.bigData ? "filled" : "empty") << std::endl;
std::cout << (box3.number ? "10" : "0") << std::endl;
std::cout << (box4.bigData ? "filled" : "empty") << std::endl;
std::cout << (box4.number ? "10" : "0") << std::endl;
std::unique_ptr<Box> uPtr1 = std::make_unique<Box>(std::move(box4));
std::cout << (uPtr1 ? "true" : "false") << std::endl;
std::unique_ptr<Box> uPtr2 = std::move(uPtr1);
std::cout << (uPtr1 ? "true" : "false") << std::endl;
std::shared_ptr<Box> sPtr1 = std::make_shared<Box>(55);
std::shared_ptr<Box> sPtr2 = sPtr1;
std::cout << *sPtr1->bigData << std::endl;
std::cout << *sPtr2->bigData << std::endl;
return 0;
}
Output:
>>empty
>>0
>>filled
>>10
>>true
>>false
>>55
>>55
Перегуд В.
No comments:
Post a Comment