Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Cynacyn
33 / 33 / 0
Регистрация: 02.05.2013
Сообщений: 109
#1

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

09.09.2013, 15:49. Просмотров 770. Ответов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.09.2013, 15:49
Здравствуйте! Я подобрал для вас темы с ответами на вопрос delete[] *pointer vs. delete pointer и утечка памяти (C++):

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

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

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

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

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

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

3
CheshireCat
Эксперт С++
2893 / 1242 / 78
Регистрация: 27.05.2008
Сообщений: 3,389
09.09.2013, 15:54 #2
Строго соблюдай соответствие операций для единичного объекта и для массива объектов:
C++
1
2
new -> delete    // для одного объекта
new[] -> delete[]    // для массива объектов
Нарушение этого правила ведет к неопределенному поведению программы.
1
ForEveR
В астрале
Эксперт С++
7979 / 4738 / 321
Регистрация: 24.06.2010
Сообщений: 10,543
Завершенные тесты: 3
09.09.2013, 17:08 #3
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
33 / 33 / 0
Регистрация: 02.05.2013
Сообщений: 109
09.09.2013, 17:59  [ТС] #4
Спасибо!
Уже отправив сообщение, я осознал что мой класс в любом случае сохранит только первый элемент из массива, поэтому использование delete [] неуместно.
0
09.09.2013, 17:59
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.09.2013, 17:59
Привет! Вот еще темы с ответами:

delete[] статической памяти - C++
1. Должна ли возникать ошибка (или падение программы) при применении delete к статической памяти? У меня (Microsoft Visual Studio 2005)...

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

Освобождение памяти delete - C++
Если у меня есть указатель (pt) N-ой степени, я присвоил ему указатель на начало массива (N - 1)ой степени (через new), затем некоторому...

Удаление памяти посредством delete[] - C++
Добрый день! Столкнулся с проблемой: при удалении выделенной памяти, программа зависает, будто не способна выполнить данный оператор....


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

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru