напомнила мне о следующем.
E>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива. E>то есть
E>
E>...
E>int i = 100;
E>foo *ptr = new foo[i];
E>...
E>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>
Читаем учебники (т.е. Страуструпа)
"Стандартная реализация new выделяет памяти немного больше, чем потребовалось бы для статического объекта. Как правило, используется одно дополнительное слово для хранения размера объекта".
напомнила мне о следующем.
E>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива. E>то есть
E>
E>...
E>int i = 100;
E>foo *ptr = new foo[i];
E>...
E>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>
E>Евгений Флоров
кол-во элементов = размер выделенной памяти/sizeof(foo), и то и другое компилеру известно.
Здравствуйте epflorov, Вы писали:
E>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива. E>то есть
E>
E>...
E>int i = 100;
E>foo *ptr = new foo[i];
E>...
E>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>
Проблема то вся в том и есть, что мы — не компилятор. Мы не знаем, а он знает. А хранит он это в некотором заголовке к выделенной памяти, т.е. выделяется на самом деле не n байт, а n + размер заголовка, и туда складывается инфа о таких вещах, как размер выделяемого блока, и, возможно, еще что-то. Таким образом, образуется некоторый overhead, зато информация присутствует и доступна в любой момент.
напомнила мне о следующем.
E>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива. E>то есть
E>
E>...
E>int i = 100;
E>foo *ptr = new foo[i];
E>...
E>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>
Ниоткуда...
В данном случае было бы неплохо сделать так:
E>...
E>int i = 100;
E>foo *ptr = new foo[i];
E>...
for(int j=0; j<i; j++)
delete(ptr[j])
напомнила мне о следующем.
E>>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива. E>>то есть
E>>
E>>...
E>>int i = 100;
E>>foo *ptr = new foo[i];
E>>...
E>>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>>
КД>Ниоткуда...
КД>В данном случае было бы неплохо сделать так:
КД>
E>>...
E>>int i = 100;
E>>foo *ptr = new foo[i];
E>>...
КД>for(int j=0; j<i; j++)
КД>delete(ptr[j])
КД>
Хммм... Рискну не согласиться.
Насколько я знаю, вполне корректный код. Т.е. деструкторы вызовутся для всех элементов массива. В этом и суть delete[].
напомнила мне о следующем.
E>>>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива. E>>>то есть
E>>>
E>>>...
E>>>int i = 100;
E>>>foo *ptr = new foo[i];
E>>>...
E>>>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>>>
КД>>Ниоткуда...
КД>>В данном случае было бы неплохо сделать так:
КД>>
E>>>...
E>>>int i = 100;
E>>>foo *ptr = new foo[i];
E>>>...
КД>>for(int j=0; j<i; j++)
КД>>delete(ptr[j])
КД>>
A>Хммм... Рискну не согласиться. A>Насколько я знаю, вполне корректный код. Т.е. деструкторы вызовутся для всех элементов массива. В этом и суть delete[].
Дополняя предыдущего оратора (Alik):
В этом и суть delete[]. — для встроенных типов данных... Для определенных вами типов (классов, структур), выделяемых "на куче", поведение delete[] может быть весьма непредсказыемым...
CMyClass* cPtr[20];
for(int i=0;i<20;i++)
cPtr[i] = new CMyClass;
delete [] cPtr; // так низзя :-))
Здравствуйте Flamer, Вы писали:
F>Здравствуйте Alik, Вы писали:
A>>Здравствуйте Койнов Дмитрий, Вы писали:
КД>>>Здравствуйте epflorov, Вы писали:
E>>>>Здравствуйте.
E>>>>Тема http://www.rsdn.ru/forum/message.asp?mid=72857
напомнила мне о следующем.
E>>>>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива. E>>>>то есть
E>>>>
E>>>>...
E>>>>int i = 100;
E>>>>foo *ptr = new foo[i];
E>>>>...
E>>>>delete []ptr; //откуда здесь становится известно о количестве элементов в массиве?
E>>>>
КД>>>Ниоткуда...
КД>>>В данном случае было бы неплохо сделать так:
КД>>>
E>>>>...
E>>>>int i = 100;
E>>>>foo *ptr = new foo[i];
E>>>>...
КД>>>for(int j=0; j<i; j++)
КД>>>delete(ptr[j])
КД>>>
A>>Хммм... Рискну не согласиться. A>>Насколько я знаю, вполне корректный код. Т.е. деструкторы вызовутся для всех элементов массива. В этом и суть delete[].
F>Дополняя предыдущего оратора (Alik):
F>В этом и суть delete[]. — для встроенных типов данных... Для определенных вами типов (классов, структур), выделяемых "на куче", поведение delete[] может быть весьма непредсказыемым...
F>
F>CMyClass* cPtr[20];
F>for(int i=0;i<20;i++)
F> cPtr[i] = new CMyClass;
F>delete [] cPtr; // так низзя :-))
F>
так здесь же удаляется память на стеке, причём тут delete[]?
F>В этом и суть delete[]. — для встроенных типов данных... Для определенных вами типов (классов, структур), выделяемых "на куче", поведение delete[] может быть весьма непредсказыемым...
F>
F>CMyClass* cPtr[20];
F>for(int i=0;i<20;i++)
F> cPtr[i] = new CMyClass;
F>delete [] cPtr; // так низзя :-))
F>
Поведение оператора delete [] предсказуемо для любых типов данных - для каждого элемента массива будет вызван деструктор. Исключение составляют встроенные типы, которые не имеют деструкторов в общем понимании.
В твоем примере массив содержит указатели, а указатели есть встроенный тип, так что delete [] здесь абсолютно не при чем.И код
CMyClass* cPtr = new CMyClass[20];
...
delete [] cPtr;
абсолютно корректен, т.е. для каждого элемента cPtr бкдет вызван деструктор.
Здравствуйте Flamer, Вы писали:
F>В этом и суть delete[]. — для встроенных типов данных... Для определенных вами типов (классов, структур), выделяемых "на куче", поведение delete[] может быть весьма непредсказыемым...
F>
F>CMyClass* cPtr[20];
F>for(int i=0;i<20;i++)
F> cPtr[i] = new CMyClass;
F>delete [] cPtr; // так низзя :-))
F>
Поясните пожалуйста.
Вы пытаетесь удалить массив выделенный в стеке?
Или Вы имели ввиду:
CMyClass* cPtr = new CMyClass[20];
for(int i=0;i<20;i++)
cPtr[i] = new CMyClass;
delete [] cPtr; // и здесь мы теряем все указатели?
E>>>>...
E>>>>int i = 100;
E>>>>foo *ptr = new foo[i];
E>>>>...
КД>>>for(int j=0; j<i; j++)
КД>>>delete(ptr[j])
КД>>>
M>>Не стОит так делать. Программа упадёт непременно. F>Не будет ли Вам сложно объяснить, почему?
Фрагмент
foo *ptr = new foo[i];
выделяет память для хранения i элементов массива, а не i блоков. В начале этого фрагмента лежит какая-то служебная информация о выделенном блоке, которая используется при удаления блока (например указатель на след блок и размер блока, необходимый для расчёта кол-ва элементов и соответственно число вызовов деструкторов). Если подсунуть опертору delete некий адрес из середины блока, то он скорее всего что-нибудь попортит, когда будет удалять его из списка блоков.
Вот задумался, а можно ли придумать хитрую реализацию, для которой бы приведённый фрагмент работал бы коректно?
Надо тщательно смотреть стандарты, чтобы ответить на этот вопрос, но скорее всего нет. Иначе надо запихивать в этот блок дополнительную информацию, что видится мне идеологически неправильным.
E>>>>>...
E>>>>>int i = 100;
E>>>>>foo *ptr = new foo[i];
E>>>>>...
КД>>>>for(int j=0; j<i; j++)
КД>>>>delete(ptr[j])
КД>>>>
и как правильно заметил Gi, ptr[i] — это объект, а не указатель, Я имел в виду, что delete(&ptr[j]) неправильно, потому что порушит цепочку блоков памяти.
напомнила мне о следующем.
E>Если мы не можем знать размер массива после его выделения, то как компилятор может вызвать деструкторы для каждого элемента массива.
Не понимаю вопроса. Мы действительно не можем знать размер массива. А компилятор — может. Деструкторы-то вызывает компилятор, а не мы.
Best regards,
Андрей Тарасевич
Re[5]: как работает delete []ptr?
От:
Аноним
Дата:
15.07.02 15:59
Оценка:
Здравствуйте Mish, Вы писали:
E>>>>>...
E>>>>>int i = 100;
E>>>>>foo *ptr = new foo[i];
E>>>>>...
КД>>>>for(int j=0; j<i; j++)
КД>>>>delete(ptr[j])
M>Вот задумался, а можно ли придумать хитрую реализацию, для которой бы приведённый фрагмент работал бы коректно?
Конечно, можно. Для этого достаточно перегрузить для класса 'foo' оператор 'new[]', оператор приведения к указателю на какой-либо тип и для этого типа оператор 'delete'. И еще — поставить ';' после 'delete(ptr[j])'.