Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++ Builder
Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.91
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
#1

Ошибка удаления дин. массива AnsiString - C++ Builder

16.02.2009, 11:49. Просмотров 2845. Ответов 15
Метки нет (Все метки)

Здравствуйте! Меня уже несколько лет приследует одна и та же проблема, которой я не могу найти решение.
Вкратце: при удалении динамического массива элементов AnsiString иногда возникает исключение "Access violation".
Более подробно это выглядит так:
Периодически возникает необходимость использовать массивы элементов, в каждом из которых есть AnsiString. Это может быть, как массив AnsiString, так массив структур, в которых есть тот же AnsiString. Для таких массивов я пишу объекты по принципу написал-отладил-зыбыл. После отладки объекта я продолжаю писать другие модули программы и вдруг ни с того, ни с сего возникает исключение на операторе delete в том самом отлаженном объекте, к которому я уже неделю не прикасаюсь. Промучившись с этим исключением два дня и ничего не решив я обычно плюю и за час переделываю все эти гребаные АнсиСтринги в char *. Только после этого я действительно забываю об объекте, потому что он начинает работать, как часы и, к тому же, быстрее. Проблема в том, что я не могу отловить эту ситуацию. Я не понимаю, почему это может происходить и как с этим бороться. Это происходит лишь иногда. Да, да! В это сложно поверить, я знаю, но жестко зафиксировать глюк не удается. Разговоры о "вылезании" за пределы выделенной памяти лишены всякого смысла, т.к. если бы у меня не было достаточно опыта, то с массивами char * я бы уж точно вылез за пределы, а с ними проблем нет. К примеру в одной из программ у меня было выделение памяти для 6 элементов AnsiString (число элементов было фиксировано константой, но массив был динамический - так было нужно). Как обычно в один прекрасные день это все захлебнулось в исключениях. После бессонной ночи я, так и не решив проблему, изменил 6 на 7 и все тут же заработало. Этот проект работает и развивается до сих пор все с той же семеркой и без глюков. Только что появилась возможность "поймать" глюк и я могу привести код, который у меня не работает. После трех нажатий на кнопку Button1 (вызов Button1Click(TObject *Sender) возникает исключение. Строка исключения помечена примечанием.

P.S. Код элементарный. Не поленитесь прочитать.
Конкретно этот код тестировался на бесплатном Turbo C++, но похожие ошибки возникали и на 5 и на 6 Builder'е.

Код
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

struct SStruct{
 AnsiString Name;
 //any other defenitions
};
//---------------------------------------------------------------------------

class CClass{
 private:
  SStruct *Struct;
  int Size;
 public:
  void Add(AnsiString Name);
  void Clear();
  CClass();
  ~CClass();
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

void CClass::Add(AnsiString Name){
 SStruct *S=new SStruct[Size+1];
 for(int i=0;i<Size;i++)S[i]=Struct[i];
 if(Size)delete Struct; // Access violation
 S[Size++].Name=Name;
 Struct=S;
};
//---------------------------------------------------------------------------

void CClass::Clear(){
 if(Size)delete Struct;
 Size=0;
};
//---------------------------------------------------------------------------

CClass::CClass(){
 Size=0;
};
//---------------------------------------------------------------------------

CClass::~CClass(){
 Clear();
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

CClass *Class;

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
 Class=new CClass;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
 delete Class;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 Class->Add(Edit1->Name);
}
//---------------------------------------------------------------------------
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
16.02.2009, 11:49
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Ошибка удаления дин. массива AnsiString (C++ Builder):

из дин. дека в дин. стек (Borland С++)
Доброй ночи. Никак не получается сделать из динамического дека - стек. Помогите...

Как перевести текст из AnsiString (в формате UTF8) в AnsiString формата Windows-1251?
Поиск по форуму не решил текущую проблему: 1. Есть текст в формате UTF-8 в...

Ошибка Cannot convert AnsiString to Bool
void __fastcall TForm3::Edit1Change(TObject *Sender) {...

ошибка в dll с классом AnsiString
Возникла такая проблема: при использовании во внутренних функциях dll типа...

сортировка массива AnsiString
подскажите как отсортировать массив AnsiString name не только по длине но и по...

Ошибка при преобразовании AnsiString в char*
TDateTime tt = DateTimePicker1-&gt;Date; char* proc_beggin_date =...

15
Alexiski
Любитель давать советы
341 / 133 / 14
Регистрация: 12.01.2009
Сообщений: 511
16.02.2009, 12:19 #2
По стандарту положено писать
C++
1
delete[] Struct;
1
Lord_Voodoo
Супер-модератор
8607 / 2228 / 133
Регистрация: 07.03.2007
Сообщений: 10,803
Завершенные тесты: 1
16.02.2009, 12:26 #3
а вы не пробывали юзать TStringList, в вашем случае он как раз подойдет...
0
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
16.02.2009, 14:08  [ТС] #4
WooDooMan, обратите внимание на
Код
//any other defenitions
в объявлении структуры. В ней может быть куча всего другого. Тот код, который я привел максимально упрощен с сохранением структуры (в смысле структуры кода, а не структуры как типа). Кстати, TStringList в том проекте, где в последний раз проявился этот глюк, тоже есть

Alexiski, спасибо. Пишу на Си уже давно, но этого не видел ни разу. Я так понял квадратные скобки нужны, чтобы прога знала, что удаляется массив, а не один элемент. Если да, то возникает вопрос: неужели я каждый раз перед удалением памяти должен проверять размер массива и, в зависимости от результата проверки, использовать либо delete, либо delete[]?
0
Vourhey
Почетный модератор
6490 / 2264 / 187
Регистрация: 29.07.2006
Сообщений: 12,534
16.02.2009, 14:19 #5
Для массивов ты всегда обязан использовать квадратные скобки. Иначе память не освобождается.
Пишу на Си уже давно, но этого не видел ни разу
Значит, ты просто не читал книги по С++. Это есть в любой книжке или статье о выделении памяти.

Добавлено через 1 минуту 35 секунд
http://cplusplus.com/doc/tutorial/dynamic.html
0
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
16.02.2009, 14:35  [ТС] #6
Цитата Сообщение от Vourhey Посмотреть сообщение
Значит, ты просто не читал книги по С++.
Почти все изучал сам.
Все-таки неясно, зачем эти скобки.
Во-первых, я так и не нашел ответа на свой предыдущий вопрос (если кто знает, подскажите), а во-вторых, из него вытекает еще один: если скобки указываются пустыми, значит компилятор (прога) знает размер массива. На хрена тогда их вообще указывать если прога знает его размер и может сама использовать delete для массивов длины 1 и delete[] для массивов длины >1?!

Добавлено через 1 минуту 27 секунд
P.S. Только что увидел ссылку. Читаю.
0
Vourhey
Почетный модератор
6490 / 2264 / 187
Регистрация: 29.07.2006
Сообщений: 12,534
16.02.2009, 14:42 #7
А откуда твоя прога узнает, что, память до этого была выделена для массива, а не для одного объекта? Ты и указываешь это. Отсюда и ответ на твои вопросы.
Почти все изучал сам.
Вот и зря
0
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
16.02.2009, 14:56  [ТС] #8
Цитата Сообщение от Vourhey Посмотреть сообщение
А откуда твоя прога узнает, что, память до этого была выделена для массива, а не для одного объекта?
А массив из одного элемента не массив уже теперь?
И все-таки про мои вопросы Что, действительно проверять каждый раз? Т.е. какая разница между использованием этих двух операторов для особождения памяти, выделенной вот так:
C++
1
int *t=new int[1];
0
Vourhey
Почетный модератор
6490 / 2264 / 187
Регистрация: 29.07.2006
Сообщений: 12,534
16.02.2009, 15:39 #9
Да, блин, ничего не проверять! Если у тебя массив:
delete [размер(не обязательно)]
если не массив
delete

Добавлено через 3 минуты 7 секунд
А массив из одного элемента не массив уже теперь?
Очень остроумно и дико смешно. Где я сказал, что массив из одного элемента, не массив? Такой же массив, такой же пойнтер. Только на единственный элемент. Читай внимательней, что там по ссылке написано.
0
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
16.02.2009, 15:40  [ТС] #10
__
0
Vourhey
Почетный модератор
6490 / 2264 / 187
Регистрация: 29.07.2006
Сообщений: 12,534
16.02.2009, 15:51 #11
Че до тебя никак не дойдет, что
C++
1
int *t=new int[10];
вернет тебе просто указатель на первый элемент: t[0]. Он вернет тебе просто int*. Откуда знать оператору delete, что ты ему передал указатель на первый элемент массива, а не просто указатель на int? Вот ты ему и указываешь, что int* это указатель только на первый элемент массива, а не на отдельный объект.

Добавлено через 9 минут 32 секунды
Yak, вообще если твоей логике следовать, то можно придраться к тому, что массив, на самом деле, не массив, а просто ряд объктов расположенных друг за другом в памяти. Ничего более...какой же это массив. А один элемент - это полюбому массив. Просто из одного элемента.
Ты что, думаешь на машинном уровне там массивы в памяти лежат? Ага, щас... Просто числа, без всяких индексов и т. д.. Просто числа в памяти. Напишу:
C++
1
2
int a=2;
int b=3;
и смело буду утверждать, что это массив. И еще обращусь к этим числам через индекс без проблем
Массив...не массив...
0
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
16.02.2009, 15:53  [ТС] #12
Цитата Сообщение от Vourhey Посмотреть сообщение
Очень остроумно и дико смешно
Хреново, если смешно...

Там по ссылке написано, что надо так! И все, а почему - не ясно.
Разложу по полочкам:
То, что вы мне объяснили очень просто и понятно, а главное максимально доступно.
1. Если выделить память для 1 элемента (объекта), то освобождать ее надо без скобок.
2. Если выделить память для массива элементов, то освобождать ее надо со скобками.
Все просто. А если я выделил память для массива, но из одного элемента?! То как? Аааа, со скобками без скобок! ...или без скобками со скобок... Хммм...

Добавлено через 51 секунду
Можете уже не париться. Я нашел http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13
0
Vourhey
Почетный модератор
6490 / 2264 / 187
Регистрация: 29.07.2006
Сообщений: 12,534
16.02.2009, 15:53 #13
все там написано, голову включи.
0
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
16.02.2009, 16:04  [ТС] #14
Цитата Сообщение от Vourhey Посмотреть сообщение
Yak, вообще если твоей логике следовать, то можно придраться к тому, что массив, на самом деле, не массив, а просто ряд объктов расположенных друг за другом в памяти. Ничего более...какой же это массив. А один элемент - это полюбому массив. Просто из одного элемента.
Ты что, думаешь на машинном уровне там массивы в памяти лежат? Ага, щас... Просто числа, без всяких индексов и т. д.. Просто числа в памяти. Напишу:
Ну вот это уже более осмысленно, хотя и поздновато.
Ладно, все равно спасибо.

Добавлено через 2 минуты 46 секунд
P.S. Да, и над речью своей Вам следует поработать. Я вам все-таки не сосед.
0
Vourhey
Почетный модератор
6490 / 2264 / 187
Регистрация: 29.07.2006
Сообщений: 12,534
16.02.2009, 16:14 #15
А так как, я уже упоминал выше, что возвращается указатель на первый элемент, то массив из одного элемента, то удалить его я могу, как мне удобней. Хотя, правильней, в любом случае будет использовать [].

P. S. мне без разницы, сосед, не сосед. Русский тоже, вроде, правильный.
0
Yak
0 / 0 / 0
Регистрация: 16.02.2009
Сообщений: 8
17.02.2009, 09:36  [ТС] #16
Цитата Сообщение от Vourhey Посмотреть сообщение
то массив из одного элемента, то удалить его я могу
Цитата Сообщение от Vourhey Посмотреть сообщение
Русский тоже, вроде, правильный


Добавлено через 14 минут 9 секунд
Вчера потестил незамысловатую программу:
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
char ***C;
int a=100,b=1000,c=100;
 
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 C=new char**[a];
 for(int i=0;i<a;i++){
    C[i]=new char*[b];
    for(int k=0;k<b;k++)
       C[i][k]=new char[c];
 }
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 for(int i=0;i<a;i++){
    for(int k=0;k<b;k++)
       delete C[i][k];
    delete C[i];
 }
 delete C;
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::Button3Click(TObject *Sender)
{
 for(int i=0;i<a;i++){
    for(int k=0;k<b;k++)
       delete[] C[i][k];
    delete[] C[i];
 }
 delete[] C;
}
//---------------------------------------------------------------------------
Button2Click и Button3Click высвобождает одинаковое кол-во памяти с точностью до килобайта. Почему - не знаю. Видимо этого не знаю не я один. Потому что вразумительного объяснения никто не дал. Если следовать логике Vourhey, то оператор delete при удалении массива char *c=new char[1000] освободит 1 байт. На практике это не так.

P.S. Alexiski отдельное спасибо. Вопрос, озвученный в шапке темы решен с его помощью.
0
17.02.2009, 09:36
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.02.2009, 09:36
Привет! Вот еще темы с решениями:

AnsiString ошибка Multiple declaration for 'str'
В идеале надо первое слово выкинуть с текста (матерное ;D) Вот я чет не пойму...

Ошибка cannon convert 'AnsiString' to 'char'
Помогите. пожалуйста. Пишу программу, нужно записать название команды и ее...

Ошибка: E2034 Cannot convert 'TStrings' to 'AnsiString'
когда программа запускается вылезает ошибка: E2034 Cannot convert 'TStrings'...

Доступ к символу элемента массива AnsiString
Здравствуйте! Как можно получить доступ к определенному символу элемента...


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

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

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