Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Динамическое выделение памяти


Автор: MAXIQ 25.2.2009, 02:46
Здравствуйте, вопрос в следующем есть ли утечка памяти в этом примере? И как ее избежать, если есть,  на Ваш взгляд? (Обработчик Button3Click)

.h
Код

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TLabel *Label1;
        TLabel *Label2;
        TButton *Button1;
        TButton *Button2;
        TLabel *Label3;
        TLabel *Label4;
        TLabel *Label5;
        TButton *Button3;
        TButton *Button4;
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall FormDestroy(TObject *Sender);
        void __fastcall Button2Click(TObject *Sender);
        void __fastcall Button4Click(TObject *Sender);
        void __fastcall Button3Click(TObject *Sender);
private:    // User declarations
public:        // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif


.cpp
Код

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
struct MyStruct
{
 int iN;
 char cStr[256];
};
GLOBALHANDLE hGlobal;
int iSchet=0; //Счетчик элементов массива структур
int iBrowse=0;//Текущий элемент массива структур
MyStruct *p; //Указатель на массив структур
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if (iSchet==0)
        {
        iSchet++;
        hGlobal=GlobalAlloc(GHND, iSchet*sizeof(MyStruct));
        //if(hGlobal==0)Label3->Caption="Нету памяти на выделение в if";
        p=(MyStruct *)GlobalLock(hGlobal);

        //Заполнение новой структуры (лишь бы заполнить))
        p[0].iN=iSchet;
        itoa(iSchet*10,p[0].cStr,10);
        //---
        Label2->Caption=(int)GlobalSize(p);
        GlobalUnlock(hGlobal);
        Label1->Caption=iSchet;
        }
 else
        {
        iSchet++;
        hGlobal=GlobalReAlloc(hGlobal,sizeof(MyStruct)*iSchet,GHND);
        p=(MyStruct *)GlobalLock(hGlobal);
        //Заполнение
        p[iSchet-1].iN=iSchet;
        itoa((iSchet*10),p[iSchet-1].cStr,10);
        //----
        Label2->Caption=GlobalSize(p);
        GlobalUnlock(hGlobal);
        Label1->Caption=iSchet;
        }
 iBrowse=iSchet;
 Label3->Caption=iSchet;
 }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
GlobalFree(hGlobal);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
if(iSchet>0)
{
if(iBrowse>0)
        {
        iBrowse--;
        p=(MyStruct *)GlobalLock(hGlobal);
        //Просмотр назад
        Label4->Caption=p[iBrowse].iN;
        Label5->Caption=p[iBrowse].cStr;
        //----
        GlobalUnlock(hGlobal);
        }
 else
        {
        iBrowse=iSchet-1;
        p=(MyStruct *)GlobalLock(hGlobal);
        //Просмотр
        Label4->Caption=p[iBrowse].iN;
        Label5->Caption=p[iBrowse].cStr;
        //----
        GlobalUnlock(hGlobal);
        }
 Label3->Caption=iSchet;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
if(iSchet>0)
{
if(iBrowse<iSchet-1)
        {
        iBrowse++;
        p=(MyStruct *)GlobalLock(hGlobal);
        //Просмотр вперед
        Label4->Caption=p[iBrowse].iN;
        Label5->Caption=p[iBrowse].cStr;
        //----
        GlobalUnlock(hGlobal);
        }
else
        {
        iBrowse=0;
        p=(MyStruct *)GlobalLock(hGlobal);
        //----
        Label4->Caption=p[iBrowse].iN;
        Label5->Caption=p[iBrowse].cStr;
        //----
        GlobalUnlock(hGlobal);
        }
Label3->Caption=iSchet;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
p=(MyStruct *)GlobalLock(hGlobal);
for(int i=iBrowse;i<iSchet;i++)
        {
        //Удаление
         if (i<iSchet-1)p[i]=p[i+1];//Вот эта строка мне покоя не дает
        //Что происходит с той областью на которое указывал p[i]? Утечки памяти нет?
        //или он так и будет болтаться в куче до перезагрузки? И надо копировать
        //структуры поэлементно?
        }
if(iSchet>1)
        {
        iSchet--;
        iBrowse--;
        if (iBrowse<0)iBrowse=iSchet-1;
        Label4->Caption=p[iBrowse].iN;
        Label5->Caption=p[iBrowse].cStr;
        hGlobal=GlobalReAlloc(hGlobal,sizeof(MyStruct)*(iSchet),GHND);
        }
GlobalUnlock(hGlobal);
Label3->Caption=iSchet;
}
//---------------------------------------------------------------------------

Автор: Artemon 26.2.2009, 08:05
Указатель на пямять, хранящийся в элементе массива p[i] - остается в памяти до выхода из программы.

Чтобы отслеживать подобные ситуации поставь в свойствах проекта галочку Code Guard и он тебе покажет где у тебя не освобождается память.

Автор: MAXIQ 26.2.2009, 18:03
Хороший знак, Code Guard молчит, возмущается только после того, как я создал объект через new и не удалил его спецом)). Однако, чтоб снять у меня все сомнения может кто сказать что с блоком памяти на который указывал p[i] происходит, указатель на него, хранившийся ранее переписан на следующий, то есть обратиться уже нельзя, но блок то вроде остался?  Или он будет заполнен если системе понадобится память так как память перемещаемая (флаг HGND)??

Автор: Artemon 26.2.2009, 18:35
Конечно останется, получится блок потерянной памяти.

Автор: Vyacheslav 26.2.2009, 19:09
У Вас указатель один. Выделенныя память предстваляет массив байтов размером  sizeof(MyStruct)*iSchet
Вот это 
Код

p[i]=p[i+1]

будет просто означать побитное копирование одной стркутуры в другую.
Память в данном случе не теряется. 
Вопрос в другом. Нафига такие сложности и переход от С++ к С?
Почему просто нельзя было решить этот вопрос с помощью new?

Автор: Artemon 27.2.2009, 09:24
Да действительно память выделяется сразу целому блоку, но меня смутила переменная iSchet, при уменьшении которой мы просто не сможем узнать начальный размер массива.
Но опятьже упустил из внимания тот факт, что при уменьшении iSchet - мы перераспределяем память.

Автор: MAXIQ 27.2.2009, 10:31
Нафига:
1. Структур может быть много.
2. Структуры довольно большие (в коде просто пример, дабы не загружать лишним)
3. Для учебных целей)))

На основании выше сказанного память решил делать перемещаемую.

Спасибо всем, очень помогли.

P.S. Вячеслав, а пример с new, чтоб были реализованы добавление, просмотр, удаление можешь сделать? Тогда тему можно считать полностью исчерпаной и мечу вопрос как решенный.

Автор: math64 27.2.2009, 11:02
Код

// Выделение памяти в первый раз (в конструкторе)
p = new MyStruct[iSchet]; // или p = NULL;
...
// Увеличение объёма памяти
MyStruct* oldP = p;
int oldSchet = iSchet;
iSchet++;
p = new MyStruct[iSchet];
memset(p, 0, sizeof(MyStruct)*iSchet);
if (oldP != NULL) {
  memcpy(p, oldP, sizeof(MyStruct)*oldSchet);
  delete oldP;
}
...
// Удаление - в деструкторе
delete p;

Автор: MAXIQ 28.2.2009, 14:09
ОК. Спасибо.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)