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

Выделение памяти под массив структур - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 20, средняя оценка - 4.85
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
06.04.2012, 11:13     Выделение памяти под массив структур #1
Возникла проблема в том что не могу никак эфективно реализовать выделение памяти под массив структур, более того: единожды выделив память я её даже освободить не могу!

Условие задания: есть класс машин (у каждой свой номер) и класс водителей (у каждого имя и фамилия). В каждом из классов есть структура TLog* что имеет вид
C++
1
2
3
4
5
    struct TLog
     {
       string m_Date;
       CCar* m_Car;//либо CDriver* m_Driver
     };
Структура позволяет хранить в классе машин кто на них ездил, а в классе пользователей на каких машинах они ездили. Класс CDriver и CCar практически полностью идентичны и проблема с выделением памяти у меня возникла и там и там, но я остановлюсь только на CCar. Выделяю я память под структуру TLog в функции usingCar (описана внизу перед main):
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//почти полная копия CCar, можно просто пролистать его
class CDriver
{
public:
    CDriver(const string& name, const string& surname)
    {
        m_Name= name;
        m_Surname= surname;
        m_LogNr= 0;
        m_Log= new TLog[1];
    }
 
 
 
    ~CDriver()
    {
        delete [] m_Log;
    }
 
    void usingCar(CCar* what, const string& when)
     {
         if(m_LogNr==0)
         {
            m_Log[0].m_Car=what;
            m_Log[0].m_Date=when;
 
            m_LogNr++;
            return;
        }
 
        TLog* tempLog=new TLog[m_LogNr+1];
        memmove(tempLog,m_Log,sizeof(TLog)*m_LogNr);
        m_Log=tempLog;
 
        m_Log[m_LogNr].m_Date=when;
        m_Log[m_LogNr].m_Car=what;
        m_LogNr++;
 
 
 
        qsort(m_Log, m_LogNr, sizeof(TLog), CDriver::compareDriversInside);
     }
 
 
     string getName() const
     {
         return (m_Name+" "+m_Surname);
     }
 
    static int compareDriversInside(const void* _first, const void* _second)
    {
        const TLog* first= (TLog*) _first;
        const TLog* second= (TLog*) _second;
        return first->m_Date.compare(second->m_Date);
    }
 
    friend ostream& operator <<(ostream& os,const CDriver& base);
protected:
    struct TLog
     {
       string m_Date;
       CCar* m_Car;
     };
 
    string m_Name;
    string m_Surname;
    TLog* m_Log;
    int m_LogNr;
 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class CCar
 {
public:
   CCar(const string& RZ)
   {
       m_RZ=RZ;
       m_LogNr=0;
       m_Log= new TLog[1];///выделяю память под один элемент
   }
 
   ~CCar()
   {
       delete []m_Log;
   }
 
   void usingCar(CDriver* who, const string& when);///здесь и возникает проблема, описана чуть ниже
 
    const string& getRZ() const
    {
        return m_RZ;
    }
 
    static int compareCarsInside(const void* _first, const void* _second)
    {
        const TLog* first= (TLog*) _first;
        const TLog* second= (TLog*) _second;
        return first->m_Date.compare(second->m_Date);
    }
 
    friend ostream& operator <<(ostream& os,const CCar& base);
protected:
    struct TLog
     {
       string m_Date;//когда
       CDriver* m_Driver;//кто
     };
    string m_RZ;//регистрационный номер авто
    TLog* m_Log;//структура с записями кто и когда водил авто
    int m_LogNr;//сколько записей о использовании авто у нас есть
 };
 
 ostream& operator <<(ostream& os,const CDriver& base)
{
    os<<base.m_Name<<" "<<base.m_Surname<<endl;
    for(int i=0;i<base.m_LogNr;i++)
     os<<base.m_Log[i].m_Date<<": "<<base.m_Log[i].m_Car->getRZ()<<endl;
    return os;
}
 
ostream& operator <<(ostream& os,const CCar& base)
{
    os<<base.m_RZ<<endl;
    for(int i=0;i<base.m_LogNr;i++)
     os<<base.m_Log[i].m_Date<<": "<<base.m_Log[i].m_Driver->getName()<<endl;
 
    return os;
}
 
 
 
 
//проблемы появляются здесь так как здесь происходит утечка памяти
void CCar::usingCar(CDriver* who, const string& when)
{
    if(m_LogNr==0) //память уже была выделена конструктором для первого элемента
    {
        m_Log[0].m_Driver=who;
        m_Log[0].m_Date=when;
 
        m_LogNr++;
        return;
    }
    //иначе нужно выделить память под массив на 1 больше чем был
    
    TLog* tempLog=new TLog[m_LogNr+1];
    memmove(tempLog,m_Log,sizeof(TLog)*m_LogNr);
    //m_Log не удаляется
    m_Log=tempLog;
 
    m_Log[m_LogNr].m_Date=when;
    m_Log[m_LogNr].m_Driver=who;
    
    m_LogNr++;
}
 
 
int main()
{
    CCar* car= new CCar("XYZ-123");
    CDriver* driver=new CDriver("Homer", "Simpson");
    CDriver* driver2= new CDriver("Magre", "Simpson");
    car->usingCar(driver,"3");
    car->usingCar(driver,"1");
    car->usingCar(driver2,"2");
    cout<<*car;
    delete car;
}
Сейчас как видно там происходит явная утечка памяти так как старая память не освобождается! Подскажите как же здесь поступить?

Мои попытки решений:
Пытаюсь удалять старую память - программа вываливается (но почему же?):
показать код

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//проблемы появляются здесь так как здесь происходит утечка памяти
void CCar::usingCar(CDriver* who, const string& when)
{
    if(m_LogNr==0) //память уже была выделена конструктором для первого элемента
    {
        m_Log[0].m_Driver=who;
        m_Log[0].m_Date=when;
 
        m_LogNr++;
        return;
    }
    //иначе нужно выделить память под массив на 1 больше чем был
 
    TLog* tempLog=new TLog[m_LogNr+1];
    memmove(tempLog,m_Log,sizeof(TLog)*m_LogNr);
    delete [] m_Log; //ОСВОБОЖДЕНИЕ ПАМЯТИ, приводит к тому что программа вываливается
    m_Log=tempLog;
 
    m_Log[m_LogNr].m_Date=when;
    m_Log[m_LogNr].m_Driver=who;
 
    m_LogNr++;
}

Любопытно что этот код крашиться и в vs2010, но если поменять delete [] m_Log на this->~CCar() (а деструктор как видно в коде какраз таки и выполняет delete [] m_Log) то код не будет вываливаться в vs2010 (в minigw всё равно будет вываливаться). Разве это не чудо? Но сдаваться это всё будет на g++ так что vs2010 здесь не аргумент.

Пытаюсь увеличивать ту память что была уже у меня через realloc:
realloc возвращает NULL (первый раз у меня такое чтобы он не справился)
показать код

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//проблемы появляются здесь так как здесь происходит утечка памяти
void CCar::usingCar(CDriver* who, const string& when)
{
    if(m_LogNr==0) //память уже была выделена конструктором для первого элемента
    {
        m_Log[0].m_Driver=who;
        m_Log[0].m_Date=when;
 
        m_LogNr++;
        return;
    }
    //иначе нужно выделить память под массив на 1 больше чем был
 
    m_Log= (TLog*) realloc(m_Log,sizeof(m_Log[0])*(m_LogNr+1));
    
    if(!m_Log) //эта ветка выполняется
     cout<<"ERRROR! REALLOC RETURN 0!";
 
    m_Log[m_LogNr].m_Date=when;
    m_Log[m_LogNr].m_Driver=who;
 
    m_LogNr++;
}


Так что же мне делать, подскажите пожалуйста
Подозреваю что проблемы со структурой из-за того что в структуре строка string, но какое-то же решение должно быть...
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
06.04.2012, 11:40     Выделение памяти под массив структур #2
Цитата Сообщение от Gepar Посмотреть сообщение
void usingCar(CCar* what, const string& when)
{
\\..
TLog* tempLog=new TLog[m_LogNr+1];
memmove(tempLog,m_Log,sizeof(TLog)*m_LogNr);
m_Log=tempLog;
m_Log[m_LogNr].m_Date=when;
m_Log[m_LogNr].m_Car=what;
\\..
}
А где освобождение памяти на которую указывал m_Log?

Добавлено через 1 минуту
Цитата Сообщение от Gepar Посмотреть сообщение
Пытаюсь увеличивать ту память что была уже у меня через realloc:
realloc можно вызывать, только если память вызывалась malloc/calloc.
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
06.04.2012, 11:56  [ТС]     Выделение памяти под массив структур #3
Цитата Сообщение от kazak Посмотреть сообщение
А где освобождение памяти на которую указывал m_Log?
А я почему тему создал?
Пытаюсь освободить - программа вываливается сразу на месте же. Попробуйте скомпилировать и запустить код, он полностью компилируемый, там все что нужно для компиляции есть.

Добавлено через 1 минуту
Цитата Сообщение от kazak Посмотреть сообщение
realloc можно вызывать, только если память вызывалась malloc/calloc.
Так тоже не срабатывает, я уже пробовал, чуть позже могу и код показать когда будет malloc и realloc и вновь будет крешиться.
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
06.04.2012, 11:58     Выделение памяти под массив структур #4
и правильно вываливается.
вот тут:
C++
1
 memmove(tempLog,m_Log,sizeof(TLog)*m_LogNr);
ты переносишь объекты простым копированием памяти. и при удалении старого контейнера вызываются деструкторы этих объектов и все указатели в "новых" объектах ... старые, то есть уже удаленные
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
06.04.2012, 12:06     Выделение памяти под массив структур #5
Цитата Сообщение от villu Посмотреть сообщение
и при удалении старого контейнера вызываются деструкторы этих объектов
Так в том то и дело, что старый массив структур не удаляестя.
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
06.04.2012, 12:09     Выделение памяти под массив структур #6
Цитата Сообщение от kazak Посмотреть сообщение
Так в том то и дело, что старый массив структур не удаляестя.
Цитата Сообщение от Gepar Посмотреть сообщение
Пытаюсь освободить - программа вываливается сразу на месте же.
а кто вообще научил так объекты копировать?
и почему вообще не использовать вектор, например.
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
06.04.2012, 13:07  [ТС]     Выделение памяти под массив структур #7
Цитата Сообщение от villu Посмотреть сообщение
а кто вообще научил так объекты копировать?
Жизнь научила, ничего больше не работает кроме этого же Сейчас покажу с malloc и с тупо построчным копированием.

Цитата Сообщение от villu Посмотреть сообщение
и почему вообще не использовать вектор, например.
Нельзя, это не с 0 написано, половина функций и все переменные уже были сразу назначены, а имена декларированы. Я могу лишь дописывать функции и переменные. Вообще это кусок программы, на деле это бд, отдельные места которой из-за ограничений на функции что уже были добавлены и то что нельзя менять ни параметры, ни тип возвращающихся значений выглядят вот так например:
C++
1
m_Cars[i]->usingCar(const_cast<CDriver*>(&(FindDriver(fname,sname))),right.m_Cars[i]->m_Log[j].m_Date);
Я это называю конструктор копирования или просто ужас. Но да это хоть работает, а вот описанный мной выше код работает не корректно же.

Цитата Сообщение от kazak Посмотреть сообщение
realloc можно вызывать, только если память вызывалась malloc/calloc.
Меняю конструктор по умолчанию заменяю выделение через new на выделение через malloc. Конструктор выглядит так:
C++
1
2
3
4
5
6
   CCar(const string& RZ)
   {
       m_RZ=RZ;
       m_LogNr=0;
       m_Log= (TLog*) malloc (sizeof(TLog)*10);///выделяю память под ДЕСЯТЬ элементов умышленно с запасом
   }
функция using car так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//проблемы появляются здесь так как здесь происходит утечка памяти
void CCar::usingCar(CDriver* who, const string& when)
{
    if(m_LogNr==0) //память уже была выделена конструктором для первого элемента
    {
        m_Log[0].m_Driver=who;
        m_Log[0].m_Date=when; //вот здесь при первом же вызове функции программа крашиться, видать криво выделил память malloc для строки типа string
 
        m_LogNr++;
        return;
    }
   //ничего не выделяю, у меня места и так под 10 элементов
 
    m_Log[m_LogNr].m_Date=when;
    m_Log[m_LogNr].m_Driver=who;
 
    m_LogNr++;
}
Как видите вновь ошибка ...
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
06.04.2012, 13:13     Выделение памяти под массив структур #8
malloc не вызывает конструкторов для объектов.
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
06.04.2012, 13:31  [ТС]     Выделение памяти под массив структур #9
Добавлю что если заменить memmove на memcpy то ээфекта естественно не будет никакого.
Странно кстати что вот попробовал вручную копировать все-все-все элементы и после такого копирования память удалилась нормально, но это ведь долго будет выполнятся, особенно если у меня десяток тысяч записей будет ...
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
void CCar::usingCar(CDriver* who, const string& when)
{
    if(m_LogNr==0) //память уже была выделена конструктором для первого элемента
    {
        m_Log[0].m_Driver=who;
        m_Log[0].m_Date=when;
 
        m_LogNr++;
        return;
    }
    //иначе нужно выделить память под массив на 1 больше чем был
 
    TLog* tempLog=new TLog[m_LogNr+1];
 
    for(int i=0;i<m_LogNr;i++)
    {
        tempLog[i].m_Date=m_Log[i].m_Date;
        tempLog[i].m_Driver=m_Log[i].m_Driver;
    }
    delete [] m_Log;
    m_Log=tempLog;
 
    m_Log[m_LogNr].m_Date=when;
    m_Log[m_LogNr].m_Driver=who;
 
    m_LogNr++;
}
Ну и я по прежнему хочу узнать почему здесь realloc не перевыделяет память, malloc выделяет её некорректно, а memove и memcpy лажают?

Добавлено через 5 минут
Код полностью компилируемый, если кто не верит что тот же malloc не справляется с выделением памяти - скопируйте из начала темы код полностью и поменяйте выделение памяти в конструкторе CCar с new на malloc.

Добавлено через 1 минуту
Цитата Сообщение от kazak Посмотреть сообщение
malloc не вызывает конструкторов для объектов.
И ... ? Я же через malloc выделяю память под
C++
1
2
3
4
5
    struct TLog
     {
       string m_Date;//когда
       CDriver* m_Driver;//кто
     };
Это обычная структура, у неё нет конструкторов, а CDriver* это лишь указатель, объект существует и нужно лишь держать в памяти указатель на него.

Добавлено через 36 секунд
Или нужно вызывать как-то конструктор для string?

Добавлено через 9 минут
Или это получается что из-за того что у меня string в структуре я не смогу использовать malloc/realloc потому что не смогу явно вызывать конструктор string ?
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
06.04.2012, 13:54     Выделение памяти под массив структур #10
Gepar, Не используйте malloc/calloc/realloc/free при работе с классами.
kazak
 Аватар для kazak
3029 / 2350 / 155
Регистрация: 11.03.2009
Сообщений: 5,401
06.04.2012, 14:04     Выделение памяти под массив структур #11
Цитата Сообщение от Gepar Посмотреть сообщение
Или это получается что из-за того что у меня string в структуре я не смогу использовать malloc/realloc потому что не смогу явно вызывать конструктор string ?
Ну теоритически если выделять память через malloc, то конструктор придется ручками вызывать, и деструктор перед удалением тоже. Плюс, вспомнил, что сложные структуры данных бывают POD (Plain Old Data) и non-POD типов. Для non-POD типов сишные malloc, memmov и т.д. не подходят вообще, а string это non-POD класс.
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
06.04.2012, 14:49  [ТС]     Выделение памяти под массив структур #12
Получается что кроме выделения время от времени нового массива через new побольше у мемя и вариантов то нет.
easybudda
Модератор
Эксперт С++
 Аватар для easybudda
9372 / 5422 / 914
Регистрация: 25.07.2009
Сообщений: 10,423
06.04.2012, 15:16     Выделение памяти под массив структур #13
Цитата Сообщение от Gepar Посмотреть сообщение
Получается что кроме выделения время от времени нового массива через new побольше у мемя и вариантов то нет.
Ну, если не учитывать самый разумный совет в этой теме (использовать стандартные контейнеры), то правильно - без вариантов. Но я бы ещё дальше пошёл - если это серьёзная база данных с большим количеством записей и разнообразием выборок, так лучше настоящую СУБД использовать (mSQL, MySQL, PostgreSQL, etc...). Короче, по-хорошему переписать бы весь этот кришнаитский манускрипт, всё равно толком работать не будет...
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
06.04.2012, 17:32  [ТС]     Выделение памяти под массив структур #14
Цитата Сообщение от easybudda Посмотреть сообщение
Ну, если не учитывать самый разумный совет в этой теме (использовать стандартные контейнеры), то правильно - без вариантов.
Ну я же уже писал что код не мой, stl туда нельзя засовывать нужно дописать лишь чтобы это работало.
У меня только один вопрос остался: почему после memmove и memcpy нельзя удалить память в этом случае?
Они ведь куски памяти копируют, притом копируют почти корректно - то что они скопировали можно потом нормально использовать, но нельзя удалить, но опять же таки почему? Давайте допустим что memmove сработала некорректно и не правильно скопировала данные в новый кусок памяти, но старый кусок памяти же должен оставаться таким же, верно? А он не остаётся судя по тому что после memove попытка удалить тот кусок памяти с которым поработал memove приводит к тому что программа нафиг вываливается. Я до этого читал и считал что memove копирует всё побайтово без всяких там буферов так что должна быть точная копия куска памяти же.
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
06.04.2012, 17:38     Выделение памяти под массив структур #15
почему после memmove и memcpy нельзя удалить память в этом случае?
потому что они копируют БИНАРНОЕ представление объекта. Они копируют все указатели, но не выделенную память, а после, в деструкторах, память освобождается и получаются объекты с указателями, которые указывают вникуда.

Добавлено через 1 минуту
Ну я же уже писал что код не мой, stl туда нельзя засовывать нужно дописать лишь чтобы это работало.
Ну оно у тебя и так "лишь чтобы это работает" ...
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.04.2012, 20:52     Выделение памяти под массив структур
Еще ссылки по теме:

C++ Выделение памяти под массив структур
C++ Выделение памяти под статический массив
C++ Динамическое выделение памяти под массив

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

Или воспользуйтесь поиском по форуму:
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
06.04.2012, 20:52  [ТС]     Выделение памяти под массив структур #16
Цитата Сообщение от villu Посмотреть сообщение
Ну оно у тебя и так "лишь чтобы это работает"
Беда в том что до конца не работает: сервер не жрёт его, говорит сходства 98.24 % при тестировании на идентичность ответа от того что отвечает то что я написал от того какие должны быть ответы. Ну да это уже другое, тут уже дело явно не в выделении памяти.
Ну а по выделению памяти я думал может как эфективнее выйдет сделать, но то что в структуре string всё портит так что буду банально выделять место сначала под 5 элементов, потом под 10 ...
Yandex
Объявления
06.04.2012, 20:52     Выделение памяти под массив структур
Ответ Создать тему
Опции темы

Текущее время: 19:54. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru