2010-09-02 2 views
3

Возможные Дубликаты:
How does delete[] “know” the size of the operand array?
(POD)freeing memory : is delete[] equal to delete ?О удаления, удаления [], оператор удаления(), и т.д.

Как я понимаю, следующая

class A {}; 
A* a = new A; 
// 
delete A; 

приведет к первому в вызове operator new() (глобальный или специализированный, предоставленный A) для выделения нужного объема памяти, а затем для вызова конструктора A. И когда вызывается delete, сначала вызывается деструктор A, а затем вызывается operator delete() для освобождения «правильное количество памяти».

Как я прочитал в TC++ PL, это «нужное количество памяти» определяется так:

Чтобы освободить пространство, выделенное на новые, удалять и удалить [] должен быть в состоянии определить размер от выделенного объекта. Это означает, что объект, выделенный с использованием стандартной реализации new, займет немного больше места, чем статический объект. Как правило, для хранения размера объекта используется одно слово.

Это имеет смысл. Но где это слово хранится для доступа к delete? Как раз перед адресом, указанным новым указателем? Так что delete может получить размер, подлежащий удалению, путем доступа к a-sizeof<void*>?

Можете ли вы прояснить это?

Я думаю, что ответ на этот вопрос может помочь мне понять, как работает delete []. Я понимаю, как new [] будет работать, и что delete [] сначала вызывает деструкторы «все объекты массива» и Освобождает всю эту память ...

Но как delete [] может знать размер массива?

Спасибо за полезные ответы!

+0

Я думаю, что это зависит от реализации, но более просвещенные люди, безусловно, будут более конкретными. – ereOn

+0

Безрадочный дубликат, извините. –

+0

связанный: [(POD) освобождение памяти: delete \ [\] равно удалению?] (Http://stackoverflow.com/questions/1553382/pod-freeing-memory-is-delete-equal-to-delete) – sbi

ответ

3

Все зависит от реализации.

Большинство времен работы действительно сохранит размер памяти непосредственно перед возвращенной памятью ((BYTE *)p-sizeof(size_t)), но есть и другие альтернативы. В моем собственном менеджере памяти (да, я пишу этот материал), у меня есть более сложная структура данных (с использованием указателей на связанные списки, контрольные суммы ...) перед возвращенной памятью. Фактически менеджер памяти должен решить, где хранить эту информацию.

Помимо размера выделенной памяти, новый [] также будет хранить количество экземпляров, чтобы он знал, сколько деструкторов нужно вызвать. Обычно это выходит за рамки диспетчера памяти и обычно обрабатывается самим сценарием/компилятором C++. Но опять же, когда это количество экземпляров хранится, зависит от компилятора, хотя на практике я ожидал, что это будет храниться непосредственно перед возвращенной памятью (и сразу после любых данных, хранящихся диспетчером памяти.

EDIT: Следующая небольшая утилита показывает расположение памяти до выделенной памяти:

#include <iostream> 

typedef unsigned char Byte; 

class X 
    { 
    public: 
     X() : m_value(1) {} 
     ~X() {m_value = 0;} 
    private: 
     int m_value; 
    }; 

void print(Byte *p,int offset) 
{ 
printf ("Value at %d: 0x%x (%d)\n", offset, p[offset], p[offset]); 
} 

void main() 
{ 
X *x = new X[10]; 

std::cout << "Address of x: " << x << std::endl; 
std::cout << "sizeof(X) : " << sizeof(X) << std::endl; 

Byte *p = (Byte *)x; 
print(p,-1); 
print(p,-2); 
print(p,-3); 
print(p,-4); 
print(p,-5); 
print(p,-6); 
print(p,-7); 
print(p,-8); 
print(p,-9); 
print(p,-10); 

X *y = new X; 
std::cout << "Address of y: " << y << std::endl; 

p = (Byte *)y; 
print(p,-1); 
print(p,-2); 
print(p,-3); 
print(p,-4); 
print(p,-5); 
print(p,-6); 
print(p,-7); 
print(p,-8); 
print(p,-9); 
print(p,-10); 
} 

Запуск этого дает следующий результат (в Visual Studio 2005):

Address of x: 00481DE4 
sizeof(X) : 4 
Value at -1: 0x0 (0) 
Value at -2: 0x0 (0) 
Value at -3: 0x0 (0) 
Value at -4: 0xa (10) 
Value at -5: 0xc (12) 
Value at -6: 0x0 (0) 
Value at -7: 0x2f (47) 
Value at -8: 0x8 (8) 
Value at -9: 0x2f (47) 
Value at -10: 0x98 (152) 
Address of y: 00481E70 
Value at -1: 0xc (12) 
Value at -2: 0x0 (0) 
Value at -3: 0x2f (47) 
Value at -4: 0x8 (8) 
Value at -5: 0x2a (42) 
Value at -6: 0x98 (152) 
Value at -7: 0xf8 (248) 
Value at -8: 0xb0 (176) 
Value at -9: 0x0 (0) 
Value at -10: 0x48 (72) 

вы может ясно видеть, что в первом случае (новый массив [] 'd) существует 4 байта, используемых для указания количества элементов (0,0,0,10, что составляет вместе значение 10).

Во втором случае эти байты опущены, и мы видим тот же шаблон (12,0,47,8), что и в первом случае. Я не знаю точно, где Visual C++ хранит количество выделенных байтов, но это доказывает, что количество элементов действительно хранится до возвращаемого указателя (в Visual Studio 2005).

+0

Итак, вы имеете в виду, что для 'нового OBJECT [SIZE]' мы могли бы получить что-то в памяти, например, «ОБЪЕКТ РАЗМЕРА ОБЪЕКТА»? –

+1

На самом деле SIZEOF (ОБЪЕКТ) NOFELEMENTS. NOFELEMENTS используется delete [], поэтому он знает, сколько деструкторов для вызова. SIZEOF (OBJECT) используется реализацией диспетчера памяти, чтобы узнать, сколько байтов освободится. – Patrick

+0

Thx. Но странно, что там (http://www.parashift.com/c++-faq-lite/compiler-dependencies.html#faq-38.7) они ничего не говорят о «SIZEOF (OBJECT)»: s –

Смежные вопросы