struct A
{
A() {}
~A(){}
};
A* p = new A[12];
delete p;
new и delete Выделение и освобождение памяти
Скажите, пожалуйста что я неправильно делаю. При освобождении памяти.
Выделяем память:
char **VIRTUAL = NULL;
if (VIRTUAL == NULL)
{
VIRTUAL = new char*[50];
for (i = 0; i < 50; i++)
VIRTUAL = new char[50];
}
Освобождаем:
if (VIRTUAL != NULL)
{
for (i = 0; i < 50; i++)
delete VIRTUAL;
delete VIRTUAL;
VIRTUAL = NULL;
}
С уважением, Дмитрий.
delete [] virtual;
///////////////////////////////////////////
можно сделать обертку:
class CharField{
public:
CharField()
{
pointer = new char[50];
screamer = "\a";
}
~CharField(){delete [] pointer;}
char& operator [](int index)
{
if (index < 0 || index >= 50) return screamer;
return pointer[index];
}
private:
char screamer;
char* pointer;
}
где-то в коде:
CharField VIRTUAL = new CharField[50];
// ... //
delete [] VIRTUAL;
////////////////////////////////
так и читабельнее и ошибку допустить сложнее
delete [] virtual; // ошибка в отсутствии '[]'
delete [] virtual;
[/QUOTE]
Делал так. Результат тот же. :(
За классы, спасибо огромное.
А зачем там нужен screamer?
А вообще что лучше использовать new/delete или malloc/free?
Заранее спасибо за помощь дилетанту. :)
А вообще что лучше использовать new/delete или malloc/free?
[/QUOTE]
new/delete операторы С++ (кстати с возможностю перегрузки и своего исспользования)
malloc/free - функции C.
Тоесть когда пишешь C++ проект логичнее использовать new/delete.
malloc/free конечно никто не запрещает, только использовать их вместе вот нежелательно.
for (i = 0; i < 50; i++)
delete [] VIRTUAL;
delete [] VIRTUAL;
это правильное освобождение
а в чем собственно проблема: есть утечка или падает приложение(если падает, то освобождаешь по второму разу, если утечка, то после исправления она не здесь)? :)
[QUOTE=xadd]
За классы, спасибо огромное.
А зачем там нужен screamer?
А вообще что лучше использовать new/delete или malloc/free?
Заранее спасибо за помощь дилетанту. :)[/QUOTE]
screamer позволит программе не упасть, в случае выхода за рамки массива, например:
for (int i = -10; i < 54; i++)
VIRTUAL[20] = (char)i;
delete [] VIRTUAL;
delete [] VIRTUAL;
это правильное освобождение
а в чем собственно проблема: есть утечка или падает приложение(если падает, то освобождаешь по второму разу, если утечка, то после исправления она не здесь)? :)
screamer позволит программе не упасть, в случае выхода за рамки массива, например:
for (int i = -10; i < 54; i++)
VIRTUAL[20] = (char)i;[/QUOTE]
Да. Утечка до сих пор есть. :)
Но первое время программа падала именно при моём delet'е.
Сейчас не уверен, но 99% что [] я тоже пробовал.
Сейчас выделяю и освобождаю в другом месте (не в самой этой функции, а вынес всё это) и уже не вылетает. Я конечно понимаю, что всё это сразу надо было вынести, но всё таки странно. :)
А что значит "освобождаешь по второму разу". Что может не освободиться? :)
Вот здесь вот:
http://tenisheff.ru/articles/mem_errors.htm
Написано:
В силу того, что до принятия стандарта память, распределенная операторами new и new[] освобождалась оператором delete не все знают, что в современном С++ запрещается удаление указателя, распределенного по new[] оператором delete. Для этого должен использоваться delete[]. И, соответственно, наоборот.
Многие ошибочно полагают, что этом случае вся неприятность заключается в том, что будет вызван деструктор лишь первого элемента массива, выделенного по new[], что для POD-типов (Plain Old Data) не принципиально. Однако, на самом деле, все обстоит значительно хуже. Стандарт говорит, что результатом применения «не того» delete будет неопределенное поведение программы.
С уважением, Дмитрий
malloc/free - функции C.
Тоесть когда пишешь C++ проект логичнее использовать new/delete.
malloc/free конечно никто не запрещает, только использовать их вместе вот нежелательно.[/QUOTE]
Спасибо. А то что то я совсем запутался.
Всегда new, delete писал, а тут первый раз такая вот ошибка... Вот я и задумался. :)
Но первое время программа падала именно при моём delet'е.
Сейчас не уверен, но 99% что [] я тоже пробовал.
Сейчас выделяю и освобождаю в другом месте (не в самой этой функции, а вынес всё это) и уже не вылетает. Я конечно понимаю, что всё это сразу надо было вынести, но всё таки странно. :)
С уважением, Дмитрий[/QUOTE]
утечка и "падала" несколько разные вещи:
утечка памяти - не освобожденная память в куче (например, char* p = new char[20] и delete [] p нигде не встречается)
если приложение падает, то это связано с недопустимой операцией, например, char* p; p[20] = '5';
[QUOTE=xadd]
А что значит "освобождаешь по второму разу". Что может не освободиться? :)
[/QUOTE]
если повторно пытаешься освободить участок памяти, то выбрасывается исключительная ситуация(exception),
например:
char* pointer = new char[20];
delete [] pointer; // освобождает память
delete [] pointer; // приведет к исключительной ситуации
утечка памяти - не освобожденная память в куче (например, char* p = new char[20] и delete [] p нигде не встречается)
если приложение падает, то это связано с недопустимой операцией, например, char* p; p[20] = '5';
если повторно пытаешься освободить участок памяти, то выбрасывается исключительная ситуация(exception),
например:
char* pointer = new char[20];
delete [] pointer; // освобождает память
delete [] pointer; // приведет к исключительной ситуации[/QUOTE]
Различие я понимаю. Просто так выразился неудачно. :)
Спасибо.
С уважением, Дмитрий
http://tenisheff.ru/articles/mem_errors.htm
Написано:
В силу того, что до принятия стандарта память, распределенная операторами new и new[] освобождалась оператором delete не все знают, что в современном С++ запрещается удаление указателя, распределенного по new[] оператором delete. Для этого должен использоваться delete[]. И, соответственно, наоборот.
Многие ошибочно полагают, что этом случае вся неприятность заключается в том, что будет вызван деструктор лишь первого элемента массива, выделенного по new[], что для POD-типов (Plain Old Data) не принципиально. Однако, на самом деле, все обстоит значительно хуже. Стандарт говорит, что результатом применения «не того» delete будет неопределенное поведение программы.[/QUOTE]
Может оно и так, но ты где-нибудь встречал компилятор, который в самом деле реализует это различие? Я всю жизнь вызывал обычный delete, только в некоторых случаях delete[], эти проекты компилились на всех компиляторах, мой последний и весьма большой проект я перенес из VC 2003 в 2005, а он содержал много таких ситуаций, тем не менее даже в 2005-м пашет как миленький.
Компилиться то они компилились, а мемори лики?
Не было.
Совет С++-прогерам - напишите один раз систему сборки мусора, ее же легко сделать, и забудьте о delete...
См. http://www.codenet.ru/progr/os/RAM/RAM-3.php
Не понимаю, чем ты хвастаешься?
Тем что смог микроскопом забить гвоздь?
Пишем:
Код:
имеем счастье в виде:
Цитата:
---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Assertion Failed!
Program: d:\Projects\temp\debug\temp.exe
File: dbgdel.cpp
Line: 52
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
---------------------------
Прервать Повтор Пропустить
---------------------------
Не было memoryleaks ?
Ща устроим:
Код:
struct A
{
A() { buff = new char[256]; }
~A() { delete[] buff; }
char* buff;
};
A* p = new A[12];
delete p;
{
A() { buff = new char[256]; }
~A() { delete[] buff; }
char* buff;
};
A* p = new A[12];
delete p;
[QUOTE=cheburator]
Совет С++-прогерам - напишите один раз систему сборки мусора, ее же легко сделать, и забудьте о delete...
См. http://www.codenet.ru/progr/os/RAM/RAM-3.php[/QUOTE]
Ну вообще-то это не сборщик мусора, а умный указатель и разница между ними есть. Причем это всего-лишь один из нескольких видов умных указателей.
К тому же невсегда можно и рационально использовать умные указатели, так что не стоит давать общих категоричных советов.
Вызываю функцию, которая выделяет память:
F1(HGLOBAL hG){
hG = ::GlobalAlloc(GPTR, 1024);
}
HGLOBAL h=NULL;
F1(h);
...
В функции F1 память выделяется, но после возврата из функции дескриптор обнуляется...
Подскажите, пожайлуста, как мне это дело исправить?
Берем ЛЮБУЮ книгу по С++ и начинаем читать ОСНОВЫ.
Особенно усиленно углубляемся в передачу параметров по ссылке и по значению.
typedef HANDLE HGLOBAL;
#ifdef STRICT
typedef void *HANDLE;
#else
typedef PVOID HANDLE;
#endif
typedef void *PVOID;
Пробовал сделать указатель на указатель - ошибка...
typedef HANDLE HGLOBAL;
#ifdef STRICT
typedef void *HANDLE;
#else
typedef PVOID HANDLE;
#endif
typedef void *PVOID;
Пробовал сделать указатель на указатель - ошибка...[/QUOTE]
И что, что есть...
Чтож тогда начинаем читать СНАЧАЛА про указатели.
Код:
void F1(HGLOBAL* hG)
{
*hG = ::GlobalAlloc(GPTR, 1024);
}
HGLOBAL h = NULL;
F1(&h);
{
*hG = ::GlobalAlloc(GPTR, 1024);
}
HGLOBAL h = NULL;
F1(&h);
А если быть точнее, то перекомпилировал проект - не работает (NULL).
А вот когда удалил папку Debug и заново откомпилировал - все впорядке! Странно и непонятно в чем дело...
Не понимаю, с чего ты взял, что я хвастаюсь. Просто никогда не использовал массивы объектов - всегда массивы указателей. А если объекты - то без конструкторов и деструкторов.
[QUOTE=Green]Ну вообще-то это не сборщик мусора, а умный указатель и разница между ними есть. Причем это всего-лишь один из нескольких видов умных указателей.[/QUOTE]
Тогда объясни между ними разницу.
[QUOTE=Green]К тому же не всегда можно и рационально использовать умные указатели, так что не стоит давать общих категоричных советов.[/QUOTE]
Почему же, это именно общий совет, а отдельные частные случаи, выходящие за его рамки, они и есть отдельные частные случаи.
Ну, таки в чем разница-то между сборкой мусора и умным указателем, может пояснишь или ссылку хотя бы дашь, чтобы вывести меня из состояния заблуждения? :) Я так понимаю, сборщик мусора - система, обеспечивающая автоматическое освобождение неиспользуемых областей памяти, таки вышеприведенная ссылка вполне выполняет эту функцию, или я ошибаюсь? А умный указатель, по крайней мере я так его понимал, это автоматический указатель, который удаляет объект, на который указывает, и не смотрит на то, есть ли на объект другие ссылки, т. е. std::auto_ptr. В статье, ссылку на которую я привел, функция "сборки мусора" не работает только в коллекциях, но по этому делу я как-раз таки собирался ещё одну статейку наваять...
http://www.intuit.ru/department/se/oopbases/9/10.html
http://ru.wikipedia.org/wiki/Сборщик_мусора
Цитата:
Сборщик мусора (garbage collector) - это функция исполнительной системы (runtime system) языка программирования. Сборщик мусора выполняет обнаружение и утилизацию недостижимых объектов, не нуждаясь в управлении приложением, хотя приложение может иметь в своем распоряжении различные средства контроля работы сборщика.
Цитата:
Кроме освобождения памяти, сборщик мусора также дефрагментирует (уплотняет) объекты в памяти системы, перемещая их так, что бы они занимали сплошную область памяти, что благоприятно отражается на производительности системы.
Т.о. сборщик мусора несколько не вписывается в концепцию С++ из-за его недостаточной типизированности и "привязки" к адресам памяти.
Умный указатель:
http://ru.wikipedia.org/wiki/Умный_указатель
Умных указателей существует множество, некоторые из них типизированы, например, как std::auto_ptr или boost::shared_ptr (этот кстати подсчитывет ссылки), некоторые нетипизированы, т.к. выполняют те действия, которые нужны только конкретному разработчику.
Так что перед тем, как писать очередную статью, я бы рекомендовал взглянуть на уже созданные и давно проверенные умные указатели, чтоб не городить велосипедов.
Ну не доверяю я стандартной библиотеке, что поделаешь :) К тому же, статья призвана в первую очередь именно показать устройство оперативной памяти читателю, а мой "велосипед" показывает, как могут быть устроены автоматизированные системы управления памятью. Ну, о boost::shared_ptr я не знал, виноват.
Ладно, а как быть с коллекциями, где каждый элемент - самостоятельный объект (и поэтому на него могут быть ссылки), но в то же время элементы коллекций, как правило, удаляются явно программистом? Твой boost::shared_ptr что будет с ними делать?
Ладно, а как быть с коллекциями, где каждый элемент - самостоятельный объект (и поэтому на него могут быть ссылки), но в то же время элементы коллекций, как правило, удаляются явно программистом? Твой boost::shared_ptr что будет с ними делать?[/QUOTE]
Ну, во первых, он не мой, а boost-а.
А во-вторых, каждый умный указатель, как я уже говорил, предназначен для конкретных целей. Если ты считаешь, что boost::shared_ptr подходит для решения твоей задачи, то лучше у тебя спросить, что он с ним будет делать.
Что касается коллекций, не совсем понятна задача.
Что хранится в коллекции? Указатели на некоторые объекты? ну тогда в чем проблема использовать тот же boost::shared_ptr?
Если в контейнере хранится сам объект, то не понятно при чем тут указатели? Иметь ссылки на элементы коллекции - не совсем правильное решение, на то она и коллекция. Но можно решить и эту задачу, все зависит от того, какое решение ты хочешь получить. Что должно по-твоему произойти со ссылками на элемент коллекции при его удалении? Ответов множество: ссылки могут становиться невалидными, ссылки могут быть переадресованы на некоторый объект-пустышку, владельцы ссылок могут быть уведомлены об уничтожении объекта и пр.
P.S. Кстати, в boost не один, а несколько различных смарт-поинтеров:
http://boost.org/libs/smart_ptr/smart_ptr.htm
Когда компилирую и запускаю, происходит ошибка - пишет типа того, что не установлен указатель.
Притом, если выбран тип проекта Debug, то эта ошибка возникает при вызове new, если Release, то при delete.
Помогите, в чем может быть проблема?
Телепаты все ещё в отпуске, так что придется приводить код.
Я код приводил, тема тут рядом, только никто не откликается.
1. Жуткое смешение С и С++.
1.1 В С++ лучше использовать new, а не malloc.
1.2.В С++ есть такое понятие, как контейнеры, например vector. Так что можно было не только не использовать malloc, но и не использовать new для динамических массивов.
1.3 Для текстовых файлов в С++ удобнее использовать потоки (см. fstream).
1.4 В С++ удобнее использовать специальный тип std::string, а не C-style строки char*.
2. Совершенно непонятный мне код:
IsIn=new bool;
InSignal=new double;
3. Классам, методам и переменным надо бы давать "говорящие" имена.
4. Очень много мест с большими конструкциями if if if if....
Есть и ещё не совсем красивые места, но пока этого будет достаточно. Код, как видишь, требует рефакторинга.
Поверь, он может быть значительно красивее, компактнее и читабельнее.
1. Насчет malloca - это я понял, я их все менял на new, только в одном месте по случайности оставил.
Для текстовых файлов я использовал и потоки, и средства с.
Такой вопрос: какой аналог у fwrite?
2. Насчет непонятного тебе кода.
Я сначала выделял память под массив указателей, а потом каждому из указателей выделял память строками типа InSignal=new double.
3. Насчет имен классов не согласен, тут, по-моему, все нормально.
Конечно, лучше писать код так, чтобы было красивее, самому же легче потом будет, с этим согласен. Просто программированию учился сам методом проб и ошибок.
Еще ты писал про некоторые некрасивые места, не мог бы сказать, где и что еще плохо написано? Попробую исправить код, потом буду писать дальше.
2. Насчет непонятного тебе кода.
Я сначала выделял память под массив указателей, а потом каждому из указателей выделял память строками типа InSignal=new double.
[/QUOTE]
А не проще работать с массивом? А то у тебя массив указателей, причем каждый указывает на единственный элемент...
Может, для другой задачи было бы и проще, но мне нужно именно так.
А чем диктуется такое условие?
Чтио касается остальных недочетов, то давай поступим так: ты рефакторишь те, что я уже описал и с теми, что ты согласен, и выкладываешь код, я его ещё раз просматриваю, а то сейчас очень утомительно смотреть код в его нынешнем состоянии.
Кстати, замени malloc не на new, а сразу на какой-нибудь из контейнеров.
Пока не закомментировал кучу delete, прога не работала.
Спрашивали, почему не double, а double *
Просто у меня много переменных(элементов векторов) должны всегда иметь одинаковые значения. Если без указателей изменить значение одной переменной, то трудно сделать так, чтобы другие "связанные" с ней переменные тоже поменяли значение. Может, можно со ссылками, но я не знаю, как сделать так, чтобы одна переменная ссылалась на другую после инициализации.
Насчет файлов: я передаю переменную FILE * в функции загрузки и сохранения, и не знаю, как 1). передавать потоки в функции. 2). Какой аналог у fwrite.
Выкладываю прогу: http://slil.ru/23049638
1. Не очень нравится формат файла, его можно менять?
2. не понятно, что значит
g >> c;
if(strcmp(c,"e")) continue;
и почему размер с равен 50? я так понял, что туда должен считываться только один символ.
3. Вместо while(strcmp(c,"")); наверное лучше while( !g.eof() );
4. Имена переменных и методов все так же загадочны. Не скупись на нормальные названия. Названия функций лучше начинать с соотв. глагола.
5. Непонятна избыточность NExam=Exam.size(); Ведь ты всегда можешь получить размер, зачем лишняя переменная?
6. Лично мне приятнее конструкции вида
return (a<b) ? a :b;
чем
if(a<b) return a;
return b;
7. Вместо Exam.at(x).In.at(y); красивее выглядит Exam[x].In[y];
8. Зачем тут int: x*int(ny)+y; ?
9. Некрасивая ситуация с new double. Может, решить её используя какое-то общее хранилище (или используя один из векторов как такое основное хранилище), а в остальных местах иметь соотв. индексы элементов в этом хранилище?
Т.е. в простейшем случае:
Код:
vector<double> commonDepot; // хранятся значения
vector<int> InSignal; // хранятся индексы значений в commonDepot
vector<int> Out; // хранятся индексы значений в commonDepot
vector<int> InSignal; // хранятся индексы значений в commonDepot
vector<int> Out; // хранятся индексы значений в commonDepot
ну или так
Код:
vector<double> Out; // хранятся значения
vector<int> InSignal; // хранятся индексы значений в Out
vector<int> InSignal; // хранятся индексы значений в Out
10. Для записи в файл создай поток для вывода ofstream и пиши туда, например, с помощью <<.
11. Поток передается в функции так же, как и любой другой объект. Лучше это делать по ссылке, т.е.
void func(ifstream&);
Кстати, для потока ввода лучше сразу использовать ifstream, а для вывода ofstream.
4. По поводу имен - потом буду править
10. Так не пойдет, потому что сразу пишутся цифры, и 8-байтовое число должно записаться типа –бКpeёв?, а не 0.123456. Нужен или fwrite, или его аналог
4. По поводу имен - потом буду править
[/QUOTE]
Потом будет поздно :)
Информативные имена нужны именно на этапе разработки.
[QUOTE=Нео]
10. Так не пойдет, потому что сразу пишутся цифры, и 8-байтовое число должно записаться типа –бКpeёв?, а не 0.123456. Нужен или fwrite, или его аналог[/QUOTE]
Так ты бинарный файл пишешь?
Тогда вот тебе примерчик:
Код:
Date dt = { 6, 10, 92 };
ofstream tfile( "date.dat" , ios::binary );
tfile.write( (char*)&dt, sizeof dt );
ofstream tfile( "date.dat" , ios::binary );
tfile.write( (char*)&dt, sizeof dt );
Попробую сделать основное хранилище. Можно ли его сделать статическим?
А во-вторых, каждый умный указатель, как я уже говорил, предназначен для конкретных целей. Если ты считаешь, что boost::shared_ptr подходит для решения твоей задачи, то лучше у тебя спросить, что он с ним будет делать.
Что касается коллекций, не совсем понятна задача.
Что хранится в коллекции? Указатели на некоторые объекты? ну тогда в чем проблема использовать тот же boost::shared_ptr?
Если в контейнере хранится сам объект, то не понятно при чем тут указатели? Иметь ссылки на элементы коллекции - не совсем правильное решение, на то она и коллекция. Но можно решить и эту задачу, все зависит от того, какое решение ты хочешь получить. Что должно по-твоему произойти со ссылками на элемент коллекции при его удалении? Ответов множество: ссылки могут становиться невалидными, ссылки могут быть переадресованы на некоторый объект-пустышку, владельцы ссылок могут быть уведомлены об уничтожении объекта и пр.
P.S. Кстати, в boost не один, а несколько различных смарт-поинтеров:
http://boost.org/libs/smart_ptr/smart_ptr.htm[/QUOTE]
Ладно, уговорил, поизучаю поглубже STL. Мало его знаю, это минус.
Как почитаю, выпущу еще одну статью :)
STL стоит изучить, даже не смотря на то, что boost это не STL. :)