#c++
Что-то я задумался о том, что не понимаю одной вроде тривиальной вещи. int *p = new int[20]; delete[] p; Откуда оператор delete[] узнает о том, что нужно освободить именно 20 * sizeof(int) байт? Что произойдет в результате выполнения следующего кода: #includeusing namespace std; int main() { int *p1 = new int[16]; int *p2 = p1; p1 = new int[20]; cout << p1 << " --- " << p2 << " --- " << p1 - p2 << endl; delete[] p1; delete[] p2; return 0; } и корректен ли он вообще? Вывод на консоль: 0x3d2b30 --- 0x3d2ae8 --- 18 Т.е. между выделенными областями памяти есть еще 64 разряда. Последнее число всегда четное, и минимум на 2 больше, чем размер первого массива. Еще один эксперимент (выше было на Win7/Qt/mingw), теперь Ubunto14.04/Qt/g++: int main() { int *p1 = new int[20]; int *p2 = p1; p1 = new int[20]; int i; for (i=0; i<20; i++) { p1[i] = 0xAAAAAAAA; p2[i] = 0xFFFFFFFF; } cout << "Pointers: " << p1 << " --- " << p2 << " --- " << p1 - p2 << endl; cout << "shifted pinters: " << p1 - 1 << " --- " << p1 - 2 << endl; cout << "values in skipped space: " << hex << *(p1-1) << " --- " << *(p1-2) << " --- " << *(p1-3) << " --- " << *(p1-4) << endl; cout << "values from p2 memory: " << hex << *(p1-5) << " --- " << *(p1-6) << " --- " << *(p1-7) << " --- " << *(p1-8) << endl; delete[] p1; delete[] p2; return 0; } Вывод на консоль: Pointers: 0x1ebd070 --- 0x1ebd010 --- 24 shifted pinters: 0x1ebd06c --- 0x1ebd068 values in skipped space: 0 --- 61 --- 0 --- 0 values from p2 memory: ffffffff --- ffffffff --- ffffffff --- ffffffff
Ответы
Ответ 1
Оператор "new с квадратными скобками" сохраняет информацию о количестве элементов массива. delete[] достает эту информацию и вызывает деструкторы у элементов. Компилятор может сгенерировать код для этих операторов следующим образом: // Исходный код struct A { A(); ~A(); }; A* a = new A[10]; delete[] a; //--------------------------------------------------------------- // Код, который генерирует компилятор (см. примечения ниже) // A* a = new A[10]; A* a; { // выделяем память void* _mem = malloc(sizeof(int) + 10 * sizeof(A)); // ^- выделяем дополнительную память для размера массива int* _size_ptr = (int*)_mem; *_size_ptr = 10; // сохраняем размер A* a = (A*)&_size_ptr[1]; // "a" указывает на память за сохраненным размером массива for (int i = 0; i != 10; ++i) ::operator new(a + i) A; // вызываем конструкторы } // delete[] a; { // перемещаем указатель на начало выделенной памяти int* _size_ptr = (int*)a - 1; for (int i = *_size_ptr - 1; i >= 0; --i) a[i].~A(); // вызываем деструкторы // удаляем память free(_size_ptr); } Примечание1: На самом деле вместо malloc и free вызываются функции void* operator new[](size_t bytes) и void operator delete[](void*). Но т.к. они вызывают что-то похожее на malloc/free, то в контексте данного вопроса этим можно пренебречь. Примечание2: Для обработки исключений, компилятор будет генерировать try-catch блок для new[].Ответ 2
Когда вы выделяете память к куче, аллокатор знает, сколько памяти было выделено. Эта информация находится в "голове" сегмента перед самой информацией. Когда необходимо очистить память, деалокатор берёт эту мета-информацию и удаляет данные. Хотя, это вроде как зависит от компилятора. Надо читать документацию. По поводу же второй части не совсем уверен, давно с C++ не работал, но проблемы не вижу, вроде всё корректно: int *p1 = new int[30]; // выделяется 30 элементов, указатель p1 ссылается на эту область int *p2 = p1; // указатель p2 ссылается на ту же область памяти p1 = new int[20]; // выделяется 20 элементов, указатель p1 теперь ссылается на эту область delete[] p1; // удаляем 20 элементов delete[] p2; // удаляем 30 элементов
Комментариев нет:
Отправить комментарий