Skip to content

Latest commit

 

History

History
210 lines (146 loc) · 11 KB

File metadata and controls

210 lines (146 loc) · 11 KB

Объектно-ориентированное программирование

Лабораторная работа №10. Умные указатели


Теоретическая справка

Умные указатели

Умные указатели (smart pointers) в С++ - это классы, которые представляют собой обертки над обычными указателями и автоматически управляют памятью объектов, на которые указывают. Они были введены в стандартную библиотеку С++11 и предоставляют более безопасный и удобный способ управления памятью, чем традиционные указатели.

Существует несколько различных типов умных указателей, каждый из которых реализует свой подход к управлению памятью. Наиболее распространенные типы умных указателей в С++:

  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr
  • std::auto_ptr(устаревший)

std::unique_ptr

std::unique_ptr: представляет собой уникальный указатель, который владеет объектом, на который он указывает. Это означает, что он отвечает за освобождение памяти при удалении объекта или при выходе из области видимости.

#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> ptr(new int(69)); //Создание уникального указателя
    
    return 0; //Память автоматически освобождается при выходе из области видимости
}

make_unique

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: представляет собой указатель на объект, который имеет несколько владельцев. Каждый владелец является 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_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::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::auto_ptr: устаревший тип умных указателей, который был заменен на std::unique_ptr. std::auto_ptr также представляет уникальный указатель, который владеет объектом, на который он указывает. Однако, он не обеспечивает безопасного управления памятью в некоторых случаях, что приводит к нежелательному поведению программы.

std::auto_ptr<int> myPointer(new int(1337));

// myPointer является владельцем объекта, на который он указывает
// Объект будет удален автоматически при выходе из области видимости
// Однако, auto_ptr не обеспечивает безопасного управления памятью
// Например, если скопировать auto_ptr, то оригинальный объект будет удален, 
// а копия будет указывать на невалидный адрес

Итог

Использование умных указателей может значительно упростить и обезопасить управление памятью в С++. Они предотвращают утечки памяти, связанные с неосвобожденными указателями, и упрощают процесс удаления объектов вложенных в другие объекты. Однако, важно использовать правильный тип умного указателя для каждой ситуации, чтобы избежать ошибок при работе с памятью.


Задание

  1. Добавить подсветку фигуры(перекрасить в друго цвет) при наведении на нее.
  2. Добавить вывод информации о фигуре при клике на нее.
  3. Избавиться от стандартных указателей. Создать объекты фигур используя std::unique_ptr.

Этапы выполнения

  1. Переопределить метод QWidget::mouseMoveEvent() класса вашего виджета. Подбронее тык.
  2. Добавить отслеживание движения мыши используя QWidget::setMouseTracking().
  3. Добавить в класс каждой фигуре метод для определения, лежит ли курсор внутри фигуры.
  4. Для обновления виджета и отрисовки подсвеченной фигуры использовать метод QWidget::update().
  5. Открыть гугл и искать все, что понадобится в ходе выполнения.

Вопросы

  1. Что такое умные указатели?
  2. Что такое std::shared_ptr?
  3. Что такое std::unique_ptr?
  4. Что такое std::weak_ptr?
  5. Почему не используют std::autp_ptr?
  6. Что такое make_unique и make_shared?
  7. В чем преимущество make_unique и make_shared?