Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,609

Освобождение памяти в стандартном shared_ptr

15.05.2024, 00:24. Показов 3657. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет! Правильно ли я понимаю, что стандартный shared_ptr не хранит внутри себя объект для удаления-особождения памяти, а что тогда делают конструкторы:
Code
1
2
3
4
template <class U, class D> shared_ptr (U* p, D del);
template <class D> shared_ptr (nullptr_t p, D del); 
template <class U, class D, class Alloc> shared_ptr (U* p, D del, Alloc alloc);
template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc);
Где сохраняют параметр del, alloc? Не могу понять это. Если попробовать реализовать совой тренировочный "shared_ptr", то как поступить, где хранит или как оформить deleter, если он не задан(по-умолчанию) или, если я задаю свой deleter...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
template<typename T/*, typename D = default_delete<T>*/>
class Shared_ptr
{
    friend T* operator-> <>() const noexcept;
    friend T& operator* <>() const noexcept;
    public:
        constexpr Shared_ptr() noexcept :ptr(nullptr), cnt(new std::size_t(0)), 
                                         del(nullptr) { }
        constexpr Shared_ptr(nullptr_t):Shared_ptr() { }
        template<typename T>
        explicit Shares_ptr(T* p):ptr(p), cnt(new std::size_t(1)), del(nullptr) { }
        
        template<typename T, template D>
        Shared_ptr(T* obj, D d):ptr(obj), cnt(new std::size_t(1)), 
                                          del(d) { }
        
        template<template D>
        Shared_ptr(nullptr_t p, D d):ptr(p), cnt(new std::size_t(1)), 
                                          del(d) { }
                                          
        Shared_ptr(const Shared_ptr& r) noexcept :ptr(r.ptr), cnt(r.cnt), del(r.del) 
        { ++*r.cnt; }
        
        template<typename U>
        Shared_ptr(const Shared_ptr<U>& r) noexcept : ptr(r.ptr), cnt(r.cnt), 
                                                       del(r.del) { ++*r.cnt}
        
        Shared_ptr(Shared_ptr&& r) noexcept:ptr(std::move(r.ptr)), 
                                            cnt(std::move(r.cnt)),
                                            del(std::move(r.del))
        { }
        
        template<typename U>
        Shared_ptr(Shared_ptr<U>&& r) noexcept : ptr(std::move(r.ptr)),
                                                 cnt(std::move(r.cnt)),
                                                 del(std::move(r.del))
        { }
        
        
        
        ~Shared_ptr();
        
        Shared_ptr& operator=(const Shared_ptr&);
        Shared_ptr& operator=(Shared_ptr&&) noexcept;
        
        T* get() const noexcept { return ptr; }
        
        void reset() noexcept;
        template<typename T>
        void reset(T* p);
        
        template<typename T, typename D>
        void reset(T* p, D d);
        
        std::size_t use_count() const { return *cnt; }
        
    private:
        T* ptr;
        size_t* cnt;
        //std::function<void(T*)>& D;
        
};
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.05.2024, 00:24
Ответы с готовыми решениями:

Резервирование памяти/освобождение памяти для трехмерного массива
Необходимо создать трехмерный массив (A), в котором элементы вдоль направления Z выли бы выровнены по 16 байт. Есть две проблемы: ...

Shared_ptr и классы с динамическим распределением памяти
Корректен ли класс? Не будет каких-нибудь проблем с памятью или других? Допустим, это заготовка под класс &quot;Массив&quot;. ...

Размещение памяти , освобождение памяти
Почему размещение памяти выполняется в два этапа? Почему освобождение памяти происходит в два этапа? void ZLab09::tablica2D(int w,...

6
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12928 / 6796 / 1819
Регистрация: 18.10.2014
Сообщений: 17,197
15.05.2024, 01:14
Цитата Сообщение от Liss29 Посмотреть сообщение
Правильно ли я понимаю, что стандартный shared_ptr не хранит внутри себя объект для удаления-особождения памяти
Что значит "не хранит"? Он хранит, разумеется, но не непосредственно внутри себя, а в тот разделяемом между всеми копиями указателя ресурсе, в котором хранятся и счетчики.

Цитата Сообщение от Liss29 Посмотреть сообщение
size_t* cnt;
То есть должно быть не size_t* cnt, а ЧтоТоБолееНавороченное *cnt. А уж внутри этого ЧтоТоБолееНавороченное будет спрятан и cnt, и weak_cnt, и del.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,609
15.05.2024, 05:04  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
То есть должно быть не size_t* cnt
Для простейшего случая...

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
ЧтоТоБолееНавороченное *cnt
Это какой-то тип внутри класса shared_ptr, ну, например, структура:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<typename T>
class data
{
    public:
        data():cnt(0), del(nullptr), w_cnt(0) { }
        data(nullptr_t):data() { }
        
    protected:
        counter cnt;
    //а как объявить объект удаления, что бы он работал и с deleter-ом по умолчанию и 
    //с заданным пользователем.
    void (*pDel)(T*) del; //Так не получается
    std::function(void (*)(T*)) del; //так, вроде бы, не подчёркивается красным, 
                                     //но в чём разница между void (*pDel)(T*); и 
                                     //std::function(void (*)(T*));
    weak_ptr<T> w_cnt;               //А это зачем?
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class Counter
{
    //friend std::ostream& operator<<(std::ostream& os, const Counter& obj);
    //friend std::istream& operator>>(std::istream& is, Counter& obj);
public:
    constexpr Counter():cnt(new unsigned int(0)) { }
    //Counter(const unsigned int _cnt) { cnt = _cnt; }
    
    unsigned int get_count() const { return cnt; }
 
    Counter& operator++() noexcept
    {
        ++cnt;
        return (*this);
    }
    Counter operator++(int)
    {
        Counter tmp(*this);
        ++(*this);
        return tmp;
    }
 
    Counter& operator--() noexcept
    {
        --cnt;
        return (*this);
    }
    Counter operator--(int)
    {
        Counter tmp(*this);
        --(*this);
        return tmp;
    }
 
    
 
 
    bool operator==(const Counter& r) const
    {
        return (cnt == r.cnt);
    }
    bool operator!=(const Counter& r) const
    {
        return !(*this == r);
    }
 
    ~Counter() { delete cnt; }
 
    //void print() const;
private:
    unsigned int* cnt;
    
private:
    Counter(const Counter& r) = delete;
    Counter(Counter&& r) = delete;
    Counter& operator=(const Counter& r) = delete;
    Counter& operator=(Counter&& r) = delete;
};
Только зачем...

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
А уж внутри этого ЧтоТоБолееНавороченное будет спрятан и cnt, и weak_cnt, и del.
Дык вот это меня и интересует, что должно быть в объявление del? А weak_cnt - что и самое главное зачем?

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Что значит "не хранит"?
Это я к тому, что разница между shared_ptr и unique_ptr состоит, в том числе, и в способе хранения функции удаления.
Данные классы отличаются также тем, как они позволяют пользователям переопределять свою стандартную функцию удаления. Для переопределения функции удаления класса shared_ptr достаточно предоставить ему при создании вызываемый объект или функцию reset(). У объекта класса unique_ptr, напротив, тип функции удаления является частью типа. При определении указателя unique_ptr пользователи должны предоставлять этот тип как явный аргумент шаблона.
В результате для указателя unique_ptr сложней предоставить собственную функцию удаления.
Соответственно я и думаю, если сказано, что в unique_ptr тип функции удаления это часть класса, то что тогда размещается внутри shared_ptr, хочется уточнить.
0
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
15.05.2024, 07:05
Цитата Сообщение от Liss29 Посмотреть сообщение
Где сохраняют параметр del, alloc? Не могу понять это
За это отвечает вспомогательный объект control block.
Для его изготовления используется идеома type_erasure


Пример:

https://rextester.com/FAQDU59172

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <utility>
#include <cassert>
   
struct type_erasure
{
    virtual ~type_erasure(){}
    virtual void free(void*) = 0;
};
 
template<class t, class Fn> struct control: type_erasure
{
    control(Fn c) noexcept
        : m_call(std::move(c))
    {}
    
    virtual void free(void* raw)
    {
        assert(raw);
        t* resource = static_cast<t*>(raw);
        this->m_call(resource);
    }
    
private:
    // Здесь располагаем функцию удалятор, счетчики, и тп
    Fn m_call;
};
 
template<class t> struct smart_ptr
{
    // lambda - любой функтор, у которого имеется operator(t*)
    template<class lambda> smart_ptr(t* v, lambda call_delete)
        : m_res(v)
        , m_del(new control<t, lambda>(std::move(call_delete)))
    {}
    
    smart_ptr(const smart_ptr&)            = delete;
    smart_ptr& operator=(const smart_ptr&) = delete;
 
    ~smart_ptr()
    {
        assert(this->m_del);
        if(this->m_res)
            this->m_del->free(this->m_res);
        delete this->m_del;
    }
    
private:  
    t* m_res;
    type_erasure* m_del;
};
 
 
#include <iostream>
 
int main()
{
    const auto del = [](int* res) 
    {
        std::cout << "delete resource\n";
        delete res;
    };
    smart_ptr ptr(new int{1}, del);
}
Вывод в консоль:
Code
1
delete resource
1
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
15.05.2024, 08:05
Цитата Сообщение от Liss29 Посмотреть сообщение
void (*pDel)(T*) del; //Так не получается
C++
1
2
3
4
5
6
7
8
9
10
11
12
void Free(int*){};
template <typename T>
class d{
    void (*pDel)(T*)=nullptr; //
public:
    void free(T*t){ if (pDel)(*pDel)(t);}
    void set(void (*d)(T*)){ pDel = d; }
};
 
d<int> a;
int empty;
void test() { a.free(&empty); a.set(Free); a.free(&empty); }
В "экземпляр" лямбды можно что-нибудь явно или неявно захватить из контекста.
0
 Аватар для Liss29
225 / 39 / 4
Регистрация: 18.11.2012
Сообщений: 1,609
18.05.2024, 08:16  [ТС]
Интересно, а как реализовать конструктор псевдоним(aliasing constructor)? template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;
p - присваивается указателю ptr, поле данных для самопального shared_ptr, а что делать с 'x', зачем это 'x' вообще передаётся в конструктор? Конструктор очень похож на копирующий конструктор, но есть один нюанс, второй параметр, тогда это напоминает другой конструктор, конструктор с одним параметром template <class U> explicit shared_ptr (U* p);. Для начала хотелось бы узнать: зачем нужен параметр const shared_ptr<U>& x и что с ним делать в конструкторе?
0
What a waste!
 Аватар для gray_fox
1610 / 1302 / 180
Регистрация: 21.04.2012
Сообщений: 2,733
21.05.2024, 01:04
Цитата Сообщение от Liss29 Посмотреть сообщение
зачем нужен параметр const shared_ptr<U>& x
Он нужет точно затем же, зачем аналогичный параметр нужен в конструкторе копирования.
Отличие aliasing constructor только в том, что результирующий объект shared_ptr будет ссылаться не на то, на что ссылается x, а на другой объект, на который указывает p.
Но информация о владении (подсчёте ссылок) будет разделена с x - точно так же, как и в случае обычного копирования.

Цитата Сообщение от Liss29 Посмотреть сообщение
что с ним делать в конструкторе?
Для поддержки aliasing constructor (скорее всего) придётся хранить раздельно указатели на control block и на сам объект, как это сделано в 4-м посте.
Контрольный блок содежит счётчик ссылок и указатель на "оригинальный" изначально выделенный объект; дополнительный указатель на объект - то, на что действительно ссылается этот объект shared_ptr и возвращает в результате разыменования и подобного.
При такой реализации тогда нужно будет:
1. При копировании скопировать указатель на контрольный блок из x и увеличить в этом контрольном блоке количество ссылок. Указатель на объект проинициализировать тем, что в контрольном блоке.
2. В случае aliasing constructor делать то же самое, но указатель на объект инициализировать дополнительным параметром p.
3. При доступе к объекту (вызове shared_ptr::get() и подобного) использовать этот отдельный указатель, а не то, что хранится в управляющем блоке.
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
21.05.2024, 01:04
Помогаю со студенческими работами здесь

Освобождение памяти
Добрый день. Подскажите пожалуйста, почему возникает ошибка при уничтожение массива class MyClass { public: int *data; int...

Освобождение памяти
1) Так получилось, что у меня подряд появляются 4 формы. Каждый раз, как показывается следующая форма, я вызываю функцию free. В итоге...

Освобождение памяти
Маленький вопросик, как правильно освобождать память выделенную под vector&lt;...&gt;, деструктором ~vector() или методом clear() ?

Освобождение памяти в C++
Добрый день! В моей программе в функции выделяется память (new char) под символьный массив, который является элементом структуры. Это...

Освобождение памяти
Добрый день Хочу спросить по поводу освобождения памяти. У меня есть головное окно которое вызывает диалоговое. С головного...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США. Нашел на реддите интересную статью под названием «Кто-нибудь знает, где получить бесплатный компьютер или. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru