← Назад к вопросам

Как можно создать std::shared_ptr?

1.0 Junior🔥 111 комментариев
#Умные указатели и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Способы создания std::shared_ptr

std::shared_ptr — это умный указатель с подсчётом ссылок. Существует несколько способов его создания, каждый с разными гарантиями безопасности и производительности. Лучший способ — std::make_shared.

Способ 1: std::make_shared (РЕКОМЕНДУЕТСЯ)

Преимущества:

  • ✅ Один heap allocation вместо двух
  • ✅ Exception-safe при использовании в функциональных аргументах
  • ✅ Лучшая кэширование
  • ✅ Меньше фрагментации памяти
#include <memory>

class MyClass {
public:
    MyClass(int x, const std::string& s) : value(x), name(s) {}
private:
    int value;
    std::string name;
};

int main() {
    auto ptr = std::make_shared<MyClass>(42, "Hello");
    ptr->getValue();
    return 0;
}

Способ 2: new + конструктор shared_ptr

Недостатки:

  • Два heap allocation (один для объекта, один для control block)
  • Может быть exception-unsafe в некоторых случаях
auto ptr = std::shared_ptr<MyClass>(new MyClass(42, "Hello"));

Способ 3: Копирование существующего shared_ptr

std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(42, "test");
std::shared_ptr<MyClass> ptr2 = ptr1;  // refcount = 2

Способ 4: Перемещение shared_ptr

std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
std::shared_ptr<MyClass> ptr2 = std::move(ptr1);
// ptr1 -> nullptr, refcount не меняется

Способ 5: Преобразование из производного класса

class Derived : public Base { };
std::shared_ptr<Derived> derived = std::make_shared<Derived>();
std::shared_ptr<Base> base = derived;  // Автоматическое преобразование

Способ 6: Динамический каст

std::shared_ptr<Base> base = std::make_shared<Derived>();
std::shared_ptr<Derived> derived = 
    std::dynamic_pointer_cast<Derived>(base);

Другие касты:

std::static_pointer_cast<T>(ptr);      // static cast
std::const_pointer_cast<T>(ptr);       // const cast
std::reinterpret_pointer_cast<T>(ptr); // reinterpret cast (C++17)

Способ 7: С кастомным deletером

auto deleter = [](MyClass* ptr) {
    // Кастомная логика очистки
    delete ptr;
};

auto ptr = std::shared_ptr<MyClass>(
    new MyClass(),
    deleter
);

Сравнение способов

МетодБезопасностьПроизводительностьРекомендация
make_sharedОтличнаяБыстроДА
new + конструкторХорошаяМедленноТолько если нужен deleter
КопированиеБезопасноКопияРедко
ПеремещениеБезопасноБыстроЧасто

Пример: Фабрика

class ObjectFactory {
public:
    static std::shared_ptr<MyClass> create(int x, const std::string& s) {
        return std::make_shared<MyClass>(x, s);
    }
};

int main() {
    auto obj = ObjectFactory::create(42, "test");
    std::vector<std::shared_ptr<MyClass>> collection;
    collection.push_back(obj);  // refcount увеличится
    return 0;
}

Лучшие практики

ДА:

  • Используй std::make_shared по умолчанию
  • Перемещай shared_ptr, не копируй
  • Используй weak_ptr для избежания циклических ссылок

НЕТ:

  • Не смешивай shared_ptr и raw pointers
  • Не создавай разные shared_ptr на один объект
  • Не используй this в конструкторе для создания shared_ptr

std::make_shared — это gold standard для создания управляемых объектов в современном C++.