Задать вопрос
Daniro_San
@Daniro_San
Программист

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

Всегда в плюсах старался заменять указатели на const T& или &T.
Единственное где их нельзя заменить - это возврат сырого массива из функции, но и тут всегда можно использовать std::vector.
Начал подробнее изучать C++11, C++14 по книге Мейерса "Эффективный и современный C++", там проталкиваются умные указатели, как я понял классы-оболочки над сырыми, с своим поведением. Так вот, как их использовать, я понял. Но где их можно использовать?
Почему бы не продолжать использовать T& и const T& вместе с std::vector ?
  • Вопрос задан
  • 649 просмотров
Подписаться 1 Оценить Комментировать
Решения вопроса 2
@Xano
Если Вы не знаете, зачем Вам умные указатели - они Вам не нужны.
Наверное, самое важное их свойство - гарантия того, что объект не разрушится, пока есть умный указатель + возможность разрушения объекта в произвольном месте, когда он уже точно никому не нужен.
Один из примеров, где умные указатели оправданы - использование нескольких потоков для выполнения операций с одним объектом.
Ответ написан
Комментировать
Есть задачи, которые не имеют решения на ссылках (либо это решение в разы хуже, чем если бы мы использовали указатели).
Пример: паттерн стратегия
#include <iostream>
#include <memory>

class Strategy {
public:
    virtual void doAction() = 0;
};

class FirstStrategy : public Strategy{
public:
    void doAction() override {
        std::cout << "First" << std::endl;
    }
};

class SecondStrategy : public Strategy{
public:
    void doAction() override {
        std::cout << "Second" << std::endl;
    }
};

class A {
    std::shared_ptr<Strategy> behavior;

public:
    void setBehavior(std::shared_ptr<Strategy> b) {
        behavior = b;
    }

    void doBehavior() {
        behavior->doAction();
    }

};

int main() {
    A a;
    a.setBehavior(std::make_shared<FirstStrategy>());
    a.doBehavior();

    a.setBehavior(std::make_shared<SecondStrategy>());
    a.doBehavior();
    return 0;
}


Во время исполнения стратегия может меняться. Так как ссылку изменить нельзя, придется создавать какие-то костыли. С указателями все проще: просто обновляем значение переменной
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Nipheris
@Nipheris Куратор тега C++
Вы, возможно, еще недостаточно освоили ОО-возможности языка C++. Тогда ваш вопрос более чем логичен.

Видите ли, в языке, где есть какая-либо ОО-модель, неизбежно будут выделяться две категории типов данных - типы данных, экзмепляры которых ведут себя как значения (values), и типы данных, экземпляры которых ведут себя как переменные/объекты (если тут непонятно, опишу подробнее).

Отличительной особенностью объекта с теоретической точки зрения является identity - некий ключ или признак, с помощью которого этот объект уникальным образом идентифицируется. В ОО базах данных в качестве identity используется т.н. OID. В C++ в качестве identity объектов используются указатели. Это удобно, т.к. место объекта в памяти однозначно идентифицирует его (тут как раз и прослеживается тот факт, что объекты в C++ - это суть переменные, изменять состояние которых можно только строго определенным образом).

Хотя язык C++ позволяет в теории работать с любым типом как "по значению", так и посредством указателей, реальные классы обычно проектируются так, чтобы подчеркнуть их семантику значение/объект. Например, для типов которые ведут себя как "значения" пишется конструктор копирования и разрешаются операции присвоения. Для типов-"объектов" наоборот, операция присвоения и конструктор копирования запрещаются. Конечно, ничто не мешает превратить указатель в ссылку и работать по ссылке, однако использование ссылки "прячет" от нас информацию об identity объекта. Например, для сравнения одинаковости двух объектов (если это именно "объекты", а не "значения") достаточно сравнить лишь их identity, в терминах C++ - указатели. Если вы превратили их в ссылки, вам придется использовать операцию взятия адреса: &a == &b, что менее логично и удобно, чем сравнить обычные указатели: a == b. Кроме того, важным отличием указателя является то, что одним из его допустимых значений является nullptr, что также может быть удобным (а может и нет).

Однако, обычные указатели хоть и являются удобным способом моделирования понятия identity, они не предоставляют какой-либо помощи для управления жизненным циклом динамических переменных (коими являются большинство объектов). В результате, программисту гораздо менее удобно использовать динамические переменные, нежели автоматические. И чтобы убить двух зайцев сразу - иметь динамические переменные-объекты с гибким временем жизни и с уникальным identity, и управлять ими удобным способом - придумали умные указатели. По сути эти указатели привязывают тем или иным образом время жизни динамической переменной к структуре программы и к местам использования этих переменных путем реализации концепций владения переменной.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы