#c #memory-management #void-pointers
#c #управление памятью #указатели void
Вопрос:
#define ALIGNBUF(Length) Length % ALIGNSIZE ?
Length ALIGNSIZE - (Length % ALIGNSIZE) : Length
short NumCols;
long * ColLenArray, * OffsetArray;
ColLenArray = new long(NumCols * sizeof(long));
OffsetArray = new long(NumCols * sizeof(long));
// THIS CODE SHOULD NOT BE NEEDED TO UNDERSTAND THE PROBLEM
// BUT I HAVE INCLUDED IT JUST IN CASE
////////////////////////////////////////////////////////////
SQLColAttribute(hstmt, ((SQLUSMALLINT) i) 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, amp;ColLenArray[i]);
ColLenArray[i] = ALIGNBUF(ColLenArray[i]);
if (i)
OffsetArray[i] = OffsetArray[i-1] ColLenArray[i-1] ALIGNBUF(sizeof(SQLINTEGER));
////////////////////////////////////////////////////////////
void **DataPtr = new void*[OffsetArray[NumCols - 1] ColLenArray[NumCols - 1] ALIGNBUF(sizeof(long))];
delete []DataPtr;
Не думаю, что это можно сделать, я перепробовал все мыслимые способы.
Этот код работает, как и в запущенной программе, я просто не могу освободить память. Каждый раз, когда вызывается этот код (включается не весь код, поскольку он не имеет значения), объем памяти увеличивается. Я думаю, что удаление происходит неправильно и что void *
продолжает расти.
Я также изменил часть приведенного выше кода, основываясь на приведенных здесь рекомендациях, но при таком коде объем памяти продолжает расти.
Комментарии:
1.
ColLenArray = new long(NumCols * sizeof(long));
это опечатка? Вы делаетеColLenArray[NumCols - 1]
позже.2. @Luc Я не вижу проблемы? ColLenArray — это указатель.
3. Указатель да, но на один длинный. Вы можете индексировать только указатель на элемент массива.
4. @Luc Я также вызываю этот код после создания указателя. SQLColAttribute(hstmt, ((SQLUSMALLINT) i) 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, amp;ColLenArray[i]); ColLenArray[i] = ALIGNBUF(ColLenArray[i]);
5.@PoiXen
amp;ColLenArray[i]
— это rvalue, с помощью которого вы не можете изменять,ColLenArray
иColLenArray[i] = ALIGNBUF(...);
присваивание по-прежнему не изменяетColLenArray
и индексирует через него. Независимо от того, каким способом вы его нарезаете, вы каждый раз индексируете указатель на один long, поэтому я надеюсьi
, что (и другие смещения) всегда равны 0… Это также относится кOffsetArray
.
Ответ №1:
Вы не можете вызвать delete
на void *
.
Решение состоит в том, чтобы не приводить указатель на void**
(который new void*[...]
вам даст) к void*
. Я действительно не знаю, что должен делать ваш код, но вы пробовали изменить тип DataPtr
на void **
?
В более общем плане, избегайте void*
, насколько это возможно, C . Есть решения получше. Если вы отредактируете свой вопрос, чтобы описать, чего вы пытаетесь достичь, тогда мы, возможно, сможем что-то предложить.
Комментарии:
1. @user: Вы должны иметь возможность вызывать
delete
(илиdelete []
в данном случае) наvoid **
.2. @Oli: Разумная формулировка «Избегать void»: D 1
Ответ №2:
Вы должны стараться избегать смешивания void*
и new
. На самом деле в C new
предназначен для автоматического определения типа указателя; тогда почему бы его не использовать. По крайней мере, вы можете использовать char*
, если вы просто имеете дело с необработанными байтами.
Другой момент — это new void*[SIZE]
выделение void**
. Итак, вам следует изменить объявление на void **DataPtr
. Удалите приведение типов перед new
. Теперь вы можете delete[] DataPtr;
.
Редактировать:
В коде есть некоторые проблемы, переменные должны быть объявлены, как показано ниже:
ColLenArray = new long[NumCols * sizeof(long)]; // declare as long[] (not long())
OffsetArray = new long[NumCols * sizeof(long)];
когда вы объявляете эти переменные как, new long()
; он просто инициализирует значение и присваивает указатель на single long
.
Повреждение памяти происходит из-за того, что вы используете ColLenArray[i]
, который обращается к неверной памяти. Поскольку вы собираетесь использовать вышеуказанные переменные в качестве массивов, это должно быть new long[]
. Тогда повреждения памяти не произойдет. После использования вы должны delete[]
их.
Комментарии:
1. @iammilind изменяет void DataPtr = (void )на новый void**[OffsetArray[numCols — 1] ColLenArray[numCols — 1] ALIGNBUF(sizeof(SQLINTEGER))]; на void ** DataPtr = новый void *[OffsetArray[numCols — 1] ColLenArray[numCols — 1] ALIGNBUF(sizeof(SQLINTEGER))]; похоже, память не освобождается, проверено в диспетчере задач, и memoery продолжает обновляться при каждом вызове функции.
2. Я предложил
void** DataPtr = new void*[...];
в своем ответе. Вы пробовали это? Также при освобождении должно бытьdelete[] DataPtr;
, поскольку вы выделяете массив.
Ответ №3:
Вам просто нужен блок памяти, который вы можете передать некоторым процедурам библиотеки базы данных? Распределить таким образом:
char * buffer = new char[ len ];
len — это длина буфера в байтах. Чтобы удалить, просто выполните:
delete [] buffer;
Вы хотите, чтобы void * передавался в функцию?
void * DataPtr = static_cast< void* >( buffer );
Для получения дополнительных баллов за заслуги используйте boost для управления удалением:
boost::scoped_array< char > buffer( new char[ len ] );
… тогда вам не нужно беспокоиться об удалении. Чтобы получить буфер здесь, вам нужно:
void * DataPtr = static_cast< void* >( buffer.get() );