Я постараюсь ответить на ваш вопрос один за другим.
Разве мы не считаем, что wild card like
blockquote >(Collection<? extends E> c);
также поддерживает тип полиморфизма?№. Причина в том, что ограниченный подстановочный символ не имеет определенного типа параметра. Это неизвестно. Все это «знает», что «сдерживание» относится к типу
E
(независимо от того, что определено). Таким образом, он не может проверить и обосновать, соответствует ли предоставленное значение ограниченному типу.Таким образом, не имеет смысла иметь полиморфное поведение в подстановочных знаках.
Документ обескураживает второй объявления и способствует использованию первого синтаксиса? В чем разница между первой и второй декларацией?
blockquote>Первый вариант лучше в этом случае, так как
T
всегда ограничен, аsource
обязательно будет иметь значения (неизвестных), что подклассыT
.Итак, предположим, что вы хотите скопировать весь список чисел, первая опция будет
Collections.copy(List<Number> dest, List<? extends Number> src);
src
, по существу, может принятьList<Double>
,List<Float>
и т. д., так как существует верхняя граница параметризованного типа, найденная вdest
.Второй вариант заставит вас привязать
S
для каждого типа, который вы хотите скопировать, например поэтому//For double Collections.copy(List<Number> dest, List<Double> src); //Double extends Number. //For int Collections.copy(List<Number> dest, List<Integer> src); //Integer extends Number.
Поскольку
S
является параметризованным типом, который требует привязки.Надеюсь, это поможет.
Suppose I'm a C++ compiler, and I implement my memory management like this: I prepend every block of reserved memory with the size of the memory, in bytes. Something like this;
| size | data ... |
^
pointer returned by new and new[]
Note that, in terms of memory allocation, there is no difference between new
and new[]
: both just allocate a block of memory of a certain size.
Now how will delete[]
know the size of the array, in order to call the right number of destructors? Simply divide the size
of the memory block by sizeof(T)
, where T
is the type of elements of the array.
Now suppose I implement delete
as simply one call to the destructor, followed by the freeing of the size
bytes, then the destructors of the subsequent elements will never be called. This results in leaking resources allocated by the subsequent elements. Yet, because I do free size
bytes (not sizeof(T)
bytes), no heap corruption occurs.
Почему не может быть ответа, что он вызывает и то и другое?
Очевидно, что память просочилась, происходит ли повреждение кучи или нет.
Вернее, поскольку я могу заново реализовать новое и удалить ..... не может ли это вообще ничего не вызывать. Технически я могу вызвать новое и удалить, чтобы выполнить новое [] и удалить [].
HENCE: неопределенное поведение.
Если предполагается, что нетривиальный деструктор, который вызывается не для всех, кроме первого элемента в массиве, чтобы освободить часть памяти, вы получаете утечку памяти, поскольку эти объекты не очищаются должным образом.
Это приведет к утечке во ВСЕХ реализациях C ++ в любом случае, когда деструктор освобождает память, потому что деструктор никогда не вызывается.
В некоторых случаях это может вызвать гораздо более серьезные ошибки.
Кажется, действительно ваш вопрос: «Почему не происходит повреждения кучи?». Ответ на этот вопрос - «потому что диспетчер кучи отслеживает размеры выделенных блоков». Вернемся на минуту к C: если вы хотите выделить один int в C, вы должны сделать int * p = malloc (sizeof (int))
, если вы хотите выделить массив размером ] n
вы можете написать int * p = malloc (n * sizeof (int))
или int * p = calloc (n, sizeof (int))
. Но в любом случае вы его освободите бесплатно (p)
, независимо от того, как вы его распределили. Вы никогда не передаете размер в free (), free () просто «знает», сколько нужно освободить, потому что размер блока malloc () - ed сохраняется где-то «перед» блоком. Вернемся к C ++, new / delete и new [] / delete [] обычно реализуются в терминах malloc (хотя они и не должны быть такими, вам не следует полагаться на это). Вот почему комбинация new [] / delete не повреждает кучу - удаление освобождает нужный объем памяти, но, как объясняли все до меня, вы можете получить утечки, не вызывая нужное количество деструкторов.
Тем не менее, рассуждения о неопределенном поведении в C ++ всегда бессмысленны. Почему это важно, если комбинация new [] / delete работает, "только" утекает или вызывает повреждение кучи? Вы не должны так кодить, точка! И на практике я бы по возможности избегал ручного управления памятью - STL и ускорение существуют не просто так.
Вот почему комбинация new [] / delete не повреждает кучу - удаление освобождает нужный объем памяти, но, как объясняли все до меня, вы можете получить утечки, не вызывая нужное количество деструкторов.Тем не менее, рассуждения о неопределенном поведении в C ++ всегда бессмысленны. Почему это важно, если комбинация new [] / delete работает, "только" утекает или вызывает повреждение кучи? Вы не должны так кодить, точка! И на практике я бы по возможности избегал ручного управления памятью - STL и ускорение существуют не просто так.
Вот почему комбинация new [] / delete не повреждает кучу - удаление освобождает нужный объем памяти, но, как объясняли все до меня, вы можете получить утечки, не вызывая нужное количество деструкторов.Тем не менее, рассуждения о неопределенном поведении в C ++ всегда бессмысленны. Почему это важно, если комбинация new [] / delete работает, "только" утекает или вызывает повреждение кучи? Вы не должны так кодить, точка! И на практике я бы по возможности избегал ручного управления памятью - STL и ускорение существуют не просто так.
рассуждения о неопределенном поведении в C ++ всегда бессмысленны. Почему это важно, если комбинация new [] / delete работает, "только" утекает или вызывает повреждение кучи? Вы не должны так кодить, точка! И на практике я бы по возможности избегал ручного управления памятью - STL и ускорение существуют не просто так. рассуждения о неопределенном поведении в C ++ всегда бессмысленны. Почему это важно, если комбинация new [] / delete работает, "только" утекает или вызывает повреждение кучи? Вы не должны так кодить, точка! И на практике я бы по возможности избегал ручного управления памятью - STL и ускорение существуют не просто так.Утечка памяти может произойти, если оператор new () переопределен, а оператор new [] - нет. то же самое относится к оператору удаления / удаления []
Помимо неопределенного поведения, наиболее очевидная причина утечек заключается в том, что реализация не вызывает деструктор для всех, кроме первого объекта в массиве. Это, очевидно, приведет к утечкам, если объектам выделены ресурсы.
Это простейший из возможных классов, о которых я мог думать, приводя к такому поведению:
struct A {
char* ch;
A(): ch( new char ){}
~A(){ delete ch; }
};
A* as = new A[10]; // ten times the A::ch pointer is allocated
delete as; // only one of the A::ch pointers is freed.
PS: обратите внимание, что конструкторы не вызываются во многих других ошибках программирования, тоже: невиртуальные деструкторы базового класса, ложная зависимость от интеллектуальных указателей, ...
Сказка о смешивании new []
и delete
якобы вызвавшей утечку памяти, это всего лишь сказка. На самом деле это абсолютно бесполезно. Я не знаю, откуда он взялся, но к настоящему времени он обрел собственную жизнь и выживает как вирус, распространяются из уст в уста от одного новичка к другому.
Наиболее вероятное объяснение этой чуши о "утечке памяти" состоит в том, что с невинно наивной точки зрения разница между delete
и delete []
заключается в том, что delete
используется для уничтожения только одного объекта, а delete []
уничтожает массив объектов («множество» объектов). Наивный вывод, который обычно делается из этого, заключается в том, что первый элемент массива будет уничтожен delete
, в то время как остальные останутся, таким образом создавая предполагаемую «утечку памяти». Конечно, любой программист, имеющий хотя бы базовое представление о типичных реализациях кучи, сразу поймет, что наиболее вероятным последствием этого является повреждение кучи, а не «утечка памяти».
Другое популярное объяснение наивной теории «утечки памяти» состоит в том, что поскольку вызывается неправильное количество деструкторов, вторичная память, принадлежащая объектам в массиве, не освобождается. Это может быть правдой, но это, очевидно, очень вынужденное объяснение, которое не имеет большого значения перед лицом гораздо более серьезной проблемы с повреждением кучи.
Короче говоря, смешивание различных функций распределения - одна из тех ошибок, которые приводят к твердой, непредсказуемое и очень практичное неопределенное поведение . Любые попытки наложить какие-то конкретные ограничения на проявления этого неопределенного поведения - просто пустая трата времени и верный признак отсутствия базового понимания.
Излишне добавлять, новый / удалить
и новый [] / delete []
на самом деле два независимых механизма управления памятью, которые можно настраивать независимо. После того, как они будут настроены (путем замены необработанных функций управления памятью), нет абсолютно никакого способа даже начать предсказывать, что может случиться, если они смешаются.
Поздно для ответа, но ...
Если ваш механизм удаления заключается в простом вызове деструктора и объединении освобожденного указателя, вместе с размером, подразумеваемым sizeof , в свободный стек, затем вызов delete для фрагмента памяти, выделенного с помощью new [], приведет к потере памяти, но не к повреждению. Более сложные структуры malloc могут повредить на или обнаружение этого поведения.