Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
 Аватар для Cynacyn
35 / 35 / 7
Регистрация: 02.05.2013
Сообщений: 109

delete[] *pointer vs. delete pointer и утечка памяти

09.09.2013, 15:49. Показов 2133. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Есть класс "умного" указателя counted_ptr, который удаляет хранящийся в нём T* owned; только если кол-во владельцев (хранящееся по адресу int* use_count), будет равно одному, иначе кол-во владельцев уменьшается на единицу.
counted_ptr владеет классом Pointer_pairs. Статический член
C++
1
 static vector<Pointer_pairs> vpp;
класса counted_ptr позволяет отслеживать состояние всех объектов counted_ptr.

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Ch 19. Ex 11. Realize counted_ptr 
//------------------------------------------------------------------------------
#include <vector>
#include <algorithm>
 
using std::vector;
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
template<class T>
class counted_ptr {
    T* owned;
    int* use_case;
 
    struct Pointer_pairs {
        void* arg_ptr;
        void* owned_ptr;
        int* number_of_owners;
    
        Pointer_pairs() 
            : arg_ptr(0),
              owned_ptr(0),
              number_of_owners(0)
        {}
        Pointer_pairs(void* arg, void* own, int* num) 
            : arg_ptr(arg),
              owned_ptr(own),
              number_of_owners(num)
        {}
        ~Pointer_pairs() {}
        // for sorting in reverse order. 
        // Pointer_pairs::number_of_owners==0 goes to the end
        // so we can pop_back() them from vpp
        bool operator<(const Pointer_pairs& p) {
            return (*number_of_owners)>*(p.number_of_owners);
        }
    };
 
    static vector<Pointer_pairs> vpp;
 
public:
 
    counted_ptr() : owned(0), use_case(0) { }
    counted_ptr(T* pt) : owned(0), use_case(0)
    {
        for(int i=0; i<vpp.size(); i++)
            if(pt==vpp[i].arg_ptr) {
                owned = static_cast<T*>(vpp[i].owned_ptr);
                ++(*vpp[i].number_of_owners);
                use_case=vpp[i].number_of_owners;
 
                cout << "couted_ptr(T* pt) " << this << "->" << " for " << owned << "->" << *owned << "[" << *use_case << "]" << endl;
 
                return;
            }
 
        if (pt) owned = new T(*pt);
        else owned = pt;
 
        vpp.push_back(Pointer_pairs(pt,owned,new int(1)));
        use_case = vpp[vpp.size()-1].number_of_owners;
        
        cout << "couted_ptr(T* pt) " << this << "->" << " for " << owned << "->" << *owned << "[" << *use_case << "]" << endl;
 
    }
    counted_ptr(const counted_ptr& cp) : owned(cp.owned), use_case(cp.use_case) 
    { 
        for(int i=0; i<vpp.size(); i++)
            if(cp.owned==vpp[i].owned_ptr) {
                ++(*vpp[i].number_of_owners);
                i = vpp.size();
            }
 
        cout << "couted_ptr(const counted_ptr& cp) " << this << "->" << " for " << owned << "->" << *owned << "[" << *use_case << "]" << endl;
    }
    counted_ptr& operator=(const counted_ptr& cp) 
    {
        if(this==&cp) return *this;
 
        // line 72: if this->(*use_case) == 1, it will delete owned from free store, preventing mem. leak
        counted_ptr temp(*this); 
 
        for(int i=0; i<vpp.size(); i++)
            if(owned==vpp[i].owned_ptr) {
                --(*vpp[i].number_of_owners);
                i = vpp.size();
            }
        
        for(int i=0; i<vpp.size(); i++)
            if(cp.owned==vpp[i].owned_ptr) {
                owned = cp.owned;
                ++(*vpp[i].number_of_owners);
                use_case = vpp[i].number_of_owners;
            }
 
        cout << "counted_ptr& operator=(const counted_ptr& cp) " << this << "->" << " for " << owned << "->" << *owned << "[" << *use_case << "]" << endl;
        return *this;
    }
    ~counted_ptr() {
        if(*use_case<2) {
            cout << "~couted_ptr() " << this << "->" << " for " << owned << "->" << *owned << "[" << *use_case << "]" << endl;
            for(int i=0; i<vpp.size(); i++) 
                if(owned==vpp[i].owned_ptr) {
                    *(vpp[i].number_of_owners)=-1;
                    i = vpp.size();
                }
            std::sort(vpp.begin(),vpp.end());
            vpp.pop_back();
            cout << "~couted_ptr() " << this << "->" << " for " << owned << "->" << *owned << "[" << *use_case << "]" << endl;
        //  delete [] owned;
            delete owned;
            delete use_case;
        }
        else {
            cout << "~couted_ptr() " << this << "->" << " for " << owned << "->" << *owned << "[" << *use_case << "]" << endl;
            for(int i=0; i<vpp.size(); i++) 
                if(owned==static_cast<T*>(vpp[i].owned_ptr)) {
                    --(*vpp[i].number_of_owners);
                    i = vpp.size();
                }
            }
    }
 
 
    
    int& owner_num() const {return *use_case; }
    
    T* release() {
        for(int i=0; i<vpp.size(); i++)
            if(owned==static_cast<T*>(vpp[i].owned_ptr)) {
                --vpp[i].number_of_owners;
                i = vpp.size();
                --(*use_case);
            }
    
        T* temp = owned;
        owned = 0;
        return temp;
    }
 
    T& operator*() {return *owned;}
    const T& operator*() const {return *owned;}
    T* operator->() { return owned; }
    const T* operator->() const {return owned; }
 
 
};
//------------------------------------------------------------------------------
template<class T>
vector<class counted_ptr<T>::Pointer_pairs> counted_ptr<T>::vpp;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Вот содержание main():
C++
1
2
3
4
5
6
7
8
9
    counted_ptr<string> cp(new string("FIRST"));
    //vector<counted_ptr<string>> vcps;
    //vcps.push_back(cp);
 
    counted_ptr<string> cp2(new string("SECOND"));
    cp = cp2;
 
    cout << cp.owner_num() << endl;
    cout << cp2.owner_num() << endl;
Если в counted_ptr.h поменять строки 110 на 111, т.е. вместо delete использовать delete[], то программа будет вылетать с debug assertion failed block type is valid phead nblockuse, но если в main() раскоментировать строки 2 и 3, то программа будет выдавать ожидаемый результат как с delete так и с delete[]. По условию задачи необходимо использовать опереатор new. Можно ли очистить память выделенную при помощи new не используя delete / delete[]?

Если пользователь инициализирует объект counted_ptr при помощи указателя на массив элементов, то delete удалит память занятую только первым элементом, при это произойдет утечка памяти, правильно?
Подскажите пожалуйста как избежать утечки памяти в данной ситуации?

Заранее, спасибо!
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
09.09.2013, 15:49
Ответы с готовыми решениями:

Утечка памяти и delete
Вот накопились вопросы про утечки памяти. 1) Как проявляется утечка памяти? На многих сайтах написано что если не удалять указатели то...

Delete[] и утечка памяти
Как можно избежать вытока памяти? И вообще почкму криво работает? #include&lt;iostream&gt; #include&lt;windows.h&gt; #include&lt;ctime&gt; ...

Утечка памяти. new/delete. Всё как доктор прописал, но не работает
Всем привет! Начну сразу с кода: #include &quot;stdafx.h&quot; #include &lt;conio.h&gt; #include &lt;iostream&gt; using namespace std; class...

3
Эксперт С++
2924 / 1274 / 114
Регистрация: 27.05.2008
Сообщений: 3,465
09.09.2013, 15:54
Строго соблюдай соответствие операций для единичного объекта и для массива объектов:
C++
1
2
new -> delete    // для одного объекта
new[] -> delete[]    // для массива объектов
Нарушение этого правила ведет к неопределенному поведению программы.
1
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
09.09.2013, 17:08
Cynacyn, Стоит делать как в бусте/STL.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<typename T>
class counted_ptr
{
  /// implementation
public:
    ~counted_ptr() { delete owned; }
};
 
template<typename T>
class counted_ptr<T[]>
{
    // implementation
public:
   ~counter_ptr() { delete[] owned; }
};
Можно конечно вместо специализации мутить всякие флажки и т.д., но это имхо несколько грустнее. Но этот вариант подойдет очевидно только для варианта, если будет вызвано нечто вроде

C++
1
counted_ptr<int[10]> p(array);
Если инициализировать именно указателем на массив элементов - определить что передали именно указатель на первый элемент массива невозможно. И тут спасет только то, что пользователь должен будет либо сам подавать флажок, либо передавать указатель на функцию (ну или объект), который нужно будет вызвать при удалении (как сделано в boost::shared_ptr к примеру).
2
 Аватар для Cynacyn
35 / 35 / 7
Регистрация: 02.05.2013
Сообщений: 109
09.09.2013, 17:59  [ТС]
Спасибо!
Уже отправив сообщение, я осознал что мой класс в любом случае сохранит только первый элемент из массива, поэтому использование delete [] неуместно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
09.09.2013, 17:59
Помогаю со студенческими работами здесь

Shared_ptr - stored pointer, owned pointer
Зачем в shared_ptr нужен хранимый указатель, отличный от владеемого? И так в этом средстве, вроде как предназначенном для уменьшения...

Используя delete по указателю, возвращенному new [] или delete [] указателем, возвращаемым new
Помогите ответить на вопрос, не могу понять суть вопроса (правильно ли понимаю, что будет если выделить память в куче и затем не удалить...

В чем разница между delete и delete[]?
а можете еще по подробней рассказать про delete, точнее даже delete, чем именно отличается delete от delete, т.к. я попробовал...

Чем отличается delete[] от delete?
чем отличается? delete mas от delete mas

Очистка памяти delete[];
Есть функция ввида: void loltest(int md3) { char* randChars; int cCount; if(md3 &lt;= 0) cCount = 13; ...


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

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Загрузка PNG-файла с альфа-каналом с помощью библиотеки SDL3_image на Android
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru