Умные указатели (smart pointers) в С++ - это классы, которые представляют собой обертки над обычными указателями и автоматически управляют памятью объектов, на которые указывают. Они были введены в стандартную библиотеку С++11 и предоставляют более безопасный и удобный способ управления памятью, чем традиционные указатели.
Существует несколько различных типов умных указателей, каждый из которых реализует свой подход к управлению памятью. Наиболее распространенные типы умных указателей в С++:
- std::unique_ptr
- std::shared_ptr
- std::weak_ptr
- std::auto_ptr(устаревший)
std::unique_ptr
: представляет собой уникальный указатель, который владеет объектом, на который он указывает. Это означает, что он отвечает за освобождение памяти при удалении объекта или при выходе из области видимости.
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int> ptr(new int(69)); //Создание уникального указателя
return 0; //Память автоматически освобождается при выходе из области видимости
}
make_unique
- это функция-фабрика, которая позволяет создавать умные указатели std::unique_ptr
.
Функция make_unique
создает объект с указанными аргументами и возвращает std::unique_ptr
на этот объект. Преимущество использования make_unique
заключается в том, что создание объекта и его управляющего умного указателя происходит атомарно, что обеспечивает безопасность от исключений и позволяет избежать утечек памяти.
#include <memory>
#include <iostream>
class Player {
public:
Player(int lvl): level(lvl) {
std::cout << "Player created with level = " << lvl << std::endl;
}
~Player() {
std::cout << "Player killed" << std::endl;
}
private:
int level = 0;
}
int main() {
std::unique_ptr<Player> ptr = std::make_unique<Player>(1);
return 0;
}
std::shared_ptr
: представляет собой указатель на объект, который имеет несколько владельцев. Каждый владелец является std::shared_ptr
, который отслеживает количество ссылок на объект и освобождает память, когда последняя ссылка уничтожается.
#include <iostream>
#include <memory>
class Player {
public:
Player() {
std::cout << "Player created" << std::endl;
}
~Player() {
std::cout << "Player killed" << std::endl;
}
private:
int level = 0;
}
int main() {
std::shared_ptr<Player> ptr(new Player()); //Создание первого shared_ptr
std::shared_ptr<Player> ptr2 = ptr1; //Создание второго shared_ptr
//Который разделяет владение объектом с первым указателем
return 0; //Память автоматически освобождается при выходе
//из обласи видимости второго shared_ptr, потом первого
}
make_shared
- это функция-фабрика аналогично make_unique
, которая позволяет создавать умные указатели std::shared_ptr
.
Функция make_shared
создает объект и управляющий умный указатель std::shared_ptr
на него, используя общий объект-счетчик для управления памятью. Это позволяет сократить количество выделений памяти и уменьшить время выполнения программы.
#include <memory>
#include <iostream>
class Player {
public:
Player(int lvl) : level(lvl) {
std::cout << "Player created with level: " << lvl << std::endl;
}
~Player() {
std::cout << "Player killed" << std::endl;
}
private:
int level = 0;
}
int main() {
std::shared_ptr<Player> ptr = std::make_shared<Player>(69);
return 0;
}
В данном примере мы создаем объект класса Player
с аргументом 69 и управляющий умный указатель std::shared_ptr
на него с помощью функции make_shared
. Объект и управляющий умный указатель будут существовать, пока на них ссылаются другие объекты-указатели std::shared_ptr
или пока не будет вызван деструктор последнего из них.
Использование функций make_unique
и make_shared
рекомендуется вместо явного вызова конструкторов умных указателей или операторов new
. Это повышает безопасность программы и делает ее более производительной.
std::weak_ptr
: представляет слабую ссылку на объект, который может иметь несколько владельцев, как и std::shared_ptr
. Однако, std::weak_ptr
не увеличивает количество ссылок на объект и не отвечает за освобождение памяти. Он используется для предотвращения циклических ссылок между объектами, которые могут привести к утечкам памяти.
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> myPointer(new int(420));
std::weak_ptr<int> myWeakPointer = myPointer;
// myPointer является владельцем объекта, на который он указывает
// myWeakPointer является слабой ссылкой на объект
// Объект не будет удален, пока существует хотя бы один shared_ptr
// Для получения shared_ptr из weak_ptr необходимо использовать метод lock():
if(std::shared_ptr<int> p = myWeakPointer.lock()) {
// p указывает на объект, на который указывал myPointer
// Объект не будет удален до тех пор, пока существует p
}
}
std::auto_ptr
: устаревший тип умных указателей, который был заменен на std::unique_ptr
. std::auto_ptr
также представляет уникальный указатель, который владеет объектом, на который он указывает. Однако, он не обеспечивает безопасного управления памятью в некоторых случаях, что приводит к нежелательному поведению программы.
std::auto_ptr<int> myPointer(new int(1337));
// myPointer является владельцем объекта, на который он указывает
// Объект будет удален автоматически при выходе из области видимости
// Однако, auto_ptr не обеспечивает безопасного управления памятью
// Например, если скопировать auto_ptr, то оригинальный объект будет удален,
// а копия будет указывать на невалидный адрес
Использование умных указателей может значительно упростить и обезопасить управление памятью в С++. Они предотвращают утечки памяти, связанные с неосвобожденными указателями, и упрощают процесс удаления объектов вложенных в другие объекты. Однако, важно использовать правильный тип умного указателя для каждой ситуации, чтобы избежать ошибок при работе с памятью.
- Добавить подсветку фигуры(перекрасить в друго цвет) при наведении на нее.
- Добавить вывод информации о фигуре при клике на нее.
- Избавиться от стандартных указателей. Создать объекты фигур используя
std::unique_ptr
.
- Переопределить метод
QWidget::mouseMoveEvent()
класса вашего виджета. Подбронее тык. - Добавить отслеживание движения мыши используя
QWidget::setMouseTracking()
. - Добавить в класс каждой фигуре метод для определения, лежит ли курсор внутри фигуры.
- Для обновления виджета и отрисовки подсвеченной фигуры использовать метод
QWidget::update()
. - Открыть гугл и искать все, что понадобится в ходе выполнения.
- Что такое умные указатели?
- Что такое
std::shared_ptr
? - Что такое
std::unique_ptr
? - Что такое
std::weak_ptr
? - Почему не используют
std::autp_ptr
? - Что такое
make_unique
иmake_shared
? - В чем преимущество
make_unique
иmake_shared
?