Я не могу понять, почему следующий код C++, скомпилированный в VS2013, приводит к сбою.
#include "stdafx.h"
class A {};
void main()
{
A** arr1 = new A*[5] { new A(), new A(), new A(), new A(), new A() };
delete[] arr1;
A** arr2 = new A*[] { new A(), new A(), new A(), new A(), new A() };
delete[] arr2;
}
Первый массив инициализируется и удаляется правильно, но второй результат: "% Filename%.exe вызвало исключение точки останова" в строке delete[] arr2
за которой следует утверждение отладки:
File: f:\dd\vctools\crt\crtw32\misc\dbgheap.c
Line: 1322
Expression: _CrtIsValidHeapPointer(pUserData)
Разница между этими двумя массивами довольно очевидна: у одного есть явно заданная длина, другая - нет. Но разве компилятор не должен быть достаточно умным, чтобы определить длину из числа элементов в следующем списке инициализаторов? Потому что он делает это просто отлично, если массив состоит из необработанных объектов (то есть A* arr = new A[] { A(), A(), A() }
).
Пожалуйста, укажите мне, что я делаю неправильно или объясню причину этого.
Не учитывайте утечки памяти из элементов массива. Они удаляются в реальной программе, и эта была быстро брошена вместе для демонстрации. Авария происходит в любом случае.
Чтобы узнать, что происходит, я попытался перегрузить new
и delete
операторы. Я попытался перегрузить new[]
и delete[]
однако VS2013 говорит, что он уже определен в некотором.lib файле.. так что вам нужно будет сделать следующее. (Разумеется, я никогда не перегружал новую или удалял раньше, поэтому надеюсь, что это правильно)
Это 32-битная программа, где sizeof(int) = 4
.
#include "stdafx.h"
#include <iostream>
void* operator new(std::size_t size) //this is called..
{
std::cout << "Allocated: "<<size<<"\n";
return malloc(size);
}
void operator delete(void* ptr) //this function never gets called.
{
std::cout << "DeAllocated\n";
free(ptr);
}
int main()
{
int** arr1 = new int*[2] {new int(1), new int(2)};
delete[] arr1;
std::cout << "\n\n";
int** arr2 = new int*[] {new int(3), new int(4)};
delete[] arr2;
}
Результаты:
Allocated: 8
Allocated: 4
Allocated: 4
Allocated: 0
Allocated: 4
Allocated: 4
Итак, откуда это взялось? Хм?
Пусть первый пример изменится на:
int** arr1 = new int*[3] {new int(1), new int(2), new int(3)};
и второе:
int** arr2 = new int*[] {new int(4), new int(5), new int(6)};
Результаты:
Allocated: 12
Allocated: 4
Allocated: 4
Allocated: 4
Allocated: 0
Allocated: 4
Allocated: 4
Allocated: 4
Вы видите, что происходит сейчас? Второй, по-видимому, выделяет неправильный размер. Другими словами, я думаю, что это говорит, что arr2 имеет размер 0, тогда как arr1 имеет размер 12.. Просто догадайтесь, что мои результаты говорят lol.
[]
рассматривается как [0]
... Что довольно странно, на мой взгляд. Но почему A* arr = new A[] { A(), A(), A(), A(), A() }; delete[] arr;
(который по-прежнему выводит Allocated: 0
, кстати) удалить без проблем?
int* arr = new int[]{1, 2, 3, 4, 5};
и delete[] arr;
вылетает точно так же в VS2013 .. ну для меня по крайней мере. Даже не перегружая new
и delete
его вылетает. : S Что-то о Heap Corruption
и записи в конец массива размера 0. Опять это также компилируется в VS2013, но не в gcc / g ++ / mingw 4.8.1
g++ 2.8.1 не будет компилировать arr2:
foo8.cpp: In function ‘int main():
foo8.cpp:7:23: error: expected primary-expression before ‘] token
A** arr2 = new A*[] { new A(), new A(), new A(), new A(), new A() };
^
foo8.cpp:7:71: error: too many initializers for ‘A* [1]
A** arr2 = new A*[] { new A(), new A(), new A(), new A(), new A() };
Взятый с тем, что нашел @CantChooseUsernames, я думаю, что есть что-то тонкое о С++ 11, я не понимаю, почему это (в терминах списка инициализаторов) - это другой случай:
A arr3[] {A(),A(),A()};
который компилируется просто отлично.
delete
каждый индекс, а затемdelete[]
сам указатель массива. - Извините, не виделdisregard the memory leaks
. Странно, второе объявление массива не компилируется для меня в Mingw 4.8.1.