Вопрос: Умные указатели?

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

Худший ответ: Есть задачи, которые не имеют решения на ссылках (либо это решение в разы хуже, чем если бы мы использовали указатели).
Пример: паттерн стратегия#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;
}
Во время исполнения стратегия может меняться. Так как ссылку изменить нельзя, придется создавать какие-то костыли. С указателями все проще: просто обновляем значение переменной