Будет этот код C++ вызывать утечку памяти (бросающий новый массив)

Вы можете создать массив, который содержит необходимый тип файла и использовать $ .inArray () в jQuery, чтобы проверить, существует ли файл filetype в массиве.

var imageType = ['jpeg', 'jpg', 'png', 'gif', 'bmp'];  

// Given that file is a file object and file.type is string 
// like "image/jpeg", "image/png", or "image/gif" and so on...

if (-1 == $.inArray(file.type.split('/')[1], imageType)) {
  console.log('Not an image type');
}
10
задан LogicStuff 22 December 2015 в 22:51
поделиться

24 ответа

Технически я полагаю, что это могло вызвать проблему с несогласованными средствами выделения, хотя на практике я не знаю ни о каком компиляторе, который не сделал бы правильной вещи с этим примером.

Что еще более важно, если STRUCT где иметь (или когда-либо даваться), деструктор затем, он вызвал бы деструктор не вызвав соответствующего конструктора.

Конечно, если Вы знаете, куда pStruct прибыл из того, почему не только набирает его, удаляют для соответствия выделению:

delete [] (BYTE*) pStruct;
12
ответ дан 3 December 2019 в 13:37
поделиться

Я думаю никакой утечки памяти.

STRUCT* pStruct = (STRUCT*)new BYTE [sizeof(STRUCT) + nPaddingSize];

Это переводится в вызов выделения памяти в операционной системе, на которую возвращается указатель на ту память. В то время, когда память выделяется, размер sizeof(STRUCT) и размер nPaddingSize был бы известен для обрабатывания любых запросов выделения памяти против базовой операционной системы.

Таким образом, память, которая выделяется, "зарегистрирована" в таблицах распределения глобальной памяти операционной системы. Таблицы памяти индексируются их указателями. Таким образом в соответствующем вызове для удаления вся память, которая была первоначально выделена, свободна. (фрагментация памяти популярный предмет в этой области также).

Вы видите, компилятор C/C++ не управляет памятью, базовая операционная система.

Я соглашаюсь, что существуют более чистые методы, но OP действительно говорил, что это было унаследованным кодом.

Короче говоря, я не вижу утечку памяти, как принятый ответ полагает там, чтобы быть тем.

0
ответ дан 3 December 2019 в 13:37
поделиться

Ответ Rob Walker хорош.

Просто маленькое дополнение, если у Вас нет конструктора или/и деструкторов, таким образом, Вы в основном должны выделить и освободить блок необработанной памяти, рассматривает использование free/malloc пары.

-1
ответ дан 3 December 2019 в 13:37
поделиться

ericmayo.myopenid.com является настолько неправильным, что кто-то с достаточной репутацией должен downvote его.

C или библиотеки времени выполнения C++ управляют "кучей", которая дана ему в блоках Операционной системой, несколько как Вы указывают, Eric. Но это - обязанность разработчика указать к компилятору, какие вызовы во время выполнения должны быть выполнены к свободной памяти и возможно разрушить объекты, которые являются там. Вектор удаляет (иначе удаляют []), необходимо в этом случае, для времени выполнения C++ для отъезда "кучи" в допустимом состоянии. То, что, когда ПРОЦЕСС завершается, ОС достаточно умна для освобождения базовых блоков памяти, не является чем-то, на что должны полагаться разработчики. Это не было бы похоже на никогда вызов, удаляют вообще.

-1
ответ дан 3 December 2019 в 13:37
поделиться

Используйте новый оператор и удалите:

struct STRUCT
{
  void *operator new (size_t)
  {
    return new char [sizeof(STRUCT) + nPaddingSize];
  }

  void operator delete (void *memory)
  {
    delete [] reinterpret_cast <char *> (memory);
  }
};

void main()
{
  STRUCT *s = new STRUCT;
  delete s;
}
0
ответ дан 3 December 2019 в 13:37
поделиться

В дополнение к превосходным ответам выше, я также хотел бы добавить:

Если Ваш код работает на Linux или если бы можно скомпилировать его на Linux затем, я предложил бы выполнить его через Valgrind. Это - превосходный инструмент среди несметного числа полезных предупреждений, это производит его, также скажет Вам, когда Вы выделяете память как массив и затем освобождаете ее как немассив (и наоборот).

0
ответ дан 3 December 2019 в 13:37
поделиться

@Matt Cruikshank You должен обратить внимание и считать то, что я записал снова, потому что я никогда не предлагал не звонить, удаляют [] и просто позволяют ОС вымыться. И Вы неправы относительно библиотек времени выполнения C++, управляющих "кучей". Если бы это имело место затем, то C++ не был бы портативным, как сегодня, и отказывающее приложение никогда не очищать ОС. (подтверждающий существует ОС определенное время выполнения, которое заставляет C/C++ казаться непортативным). Я бросаю вызов Вам находить stdlib.h в источниках Linux из kernel.org. Новое ключевое слово в C++ на самом деле говорит с теми же стандартными программами управления памятью как malloc.

Библиотеки времени выполнения C++ делают системные вызовы ОС, и это - ОС, которая управляет "кучей". Вы частично корректны в этом, библиотеки времени выполнения указывают, когда освободить память однако, они на самом деле не обходят таблиц "кучи" непосредственно. Другими словами, время выполнения, против которого Вы связываетесь, не добавляет код к Вашему приложению для обхода "кучи", чтобы выделить или освободить. Дело обстоит так в Windows, Linux, Солярисе, AIX, и т.д... Это - также причина, Вы не будете прекрасный malloc в источнике ядра никакого Linux, и при этом Вы не найдете stdlib.h в источнике Linux. Поймите их, современная операционная система имеет диспетчеров виртуальной памяти, который усложняет вещи немного далее.

Когда-нибудь задавайтесь вопросом, почему можно позвонить malloc для 2G RAM на поле 1G и все еще возвратить допустимый указатель памяти?

Управление памятью на x86 процессорах организовано в пространстве Ядра с помощью трех таблиц. PAM (Таблица распределения Страницы), PD (Каталоги Страницы) и PT (Таблицы страниц). Это на аппаратном уровне, о котором я говорю. Одна из вещей, которые диспетчер памяти ОС делает, не Ваше приложение C++, состоит в том, чтобы узнать, сколько физической памяти установлено на поле во время начальной загрузки со справкой вызовов BIOS. ОС также обрабатывает исключения такой как тогда, когда Вы пытаетесь получить доступ к памяти, Ваше приложение не имеет прав также. (Общее нарушение защиты GPF).

Может случиться так, что мы говорим то же самое Matt, но я думаю, что можно путать под функциональностью капота немного. Я использую для поддержания компилятора C/C++ для жизни...

0
ответ дан 3 December 2019 в 13:37
поделиться

@ericmayo - крепы. Ну, экспериментируя с VS2005, я не могу вытащить честную утечку из скаляра, удаляют на памяти, которая была сделана новым вектором. Я предполагаю, что поведение компилятора "не определено" здесь, о лучшей защите, которую я могу собрать.

Необходимо признать, хотя, это - действительно паршивая практика, чтобы сделать что исходный сказанный плакат.

Если бы это имело место затем, то C++ не был бы портативным, как сегодня, и отказывающее приложение никогда не очищать ОС.

Эта логика действительно не содержит, все же. Мое утверждение - то, что время выполнения компилятора может управлять памятью в блоках памяти, которые ОС возвращает ему. Это - то, как большинство виртуальных машин работает, таким образом, Ваш аргумент против мобильности в этом случае не имеет большого смысла.

0
ответ дан 3 December 2019 в 13:37
поделиться

Вы - вид смешивания C и C++ способы сделать вещи. Почему выделяют больше, чем размер СТРУКТУРЫ? Почему не только "новая СТРУКТУРА"? Если необходимо сделать это затем, это могло бы быть более ясно использовать malloc и свободный в этом случае, с тех пор Вы или другие программисты могли бы быть немного менее вероятны сделать предположения о типах и размерах выделенных объектов.

0
ответ дан 3 December 2019 в 13:37
поделиться

@Matt Cruikshank

"Ну, экспериментируя с VS2005, я не могу вытащить честную утечку из скаляра, удаляют на памяти, которая была сделана новым вектором. Я предполагаю, что поведение компилятора "не определено" здесь, о лучшей защите, которую я могу собрать".

Я не соглашаюсь, что это - поведение компилятора или даже проблема компилятора. 'Новое' ключевое слово компилируется и связалось, как Вы указали к библиотекам времени выполнения. Те библиотеки времени выполнения обрабатывают вызовы управления памятью к ОС в независимом от операционной системы непротиворечивом синтаксисе, и те библиотеки времени выполнения ответственны за то, что последовательно делали malloc и новую работу между Ose, такими как Linux, Windows, Солярис, AIX, и т.д.... Это - причина, я упомянул аргумент мобильности; попытка доказать Вам, что время выполнения на самом деле не управляет памятью также.

ОС управляет памятью.

Время выполнения освобождает интерфейс к ОС.. В Windows это - диспетчер виртуальной памяти DLLs. Поэтому stdlib.h реализован в библиотеках GLIB-C а не источнике ядра Linux; если БОЙКИЙ-C используется на других Ose, это - реализация изменений malloc для совершения корректных вызовов ОС. В VS, Borland, и т.д. Вы никогда не будете находить библиотек, которые поставлются с их компиляторами, которые на самом деле управляют памятью также. Вы, однако, найдете ОС определенными определениями для malloc.

Так как у нас есть источник к Linux, можно пойти посмотреть на то, как malloc реализован там. Вы будете видеть, что malloc на самом деле реализован в компиляторе GCC, который, в свою очередь, в основном превращает два системных вызова Linux в ядро для выделения памяти. Никогда, malloc самостоятельно, на самом деле руководящая память!

И не берите его от меня. Считайте исходный код в Linux ОС, или Вы видите то, что K&R говорят об этом... Вот ссылка PDF на K&R на C.

http://www.oberon2005.ru/paper/kr_c.pdf

Посмотрите ближний конец Страницы 149: "Вызовы к malloc и свободный могут произойти в любом порядке; malloc призывает операционную систему получать больше памяти по мере необходимости. Эти стандартные программы иллюстрируют некоторые соображения, вовлеченные в запись машинно-зависимого кода относительно машинно-независимым способом, и также показывают реальное применение структур, объединений и определения типа".

"Необходимо признать, хотя, это - действительно паршивая практика, чтобы сделать что исходный сказанный плакат".

О, я не не соглашаюсь там. Моя точка была то, что код исходного плаката не способствовал из утечки памяти. Это - все, что я говорил. Я не вмешался на стороне лучшей практики вещей. Так как код звонит, удаляют, память освобождается.

Я соглашаюсь в Вашей защите, если код исходного плаката никогда не выходил или никогда не добирался до удалить вызова, что код мог иметь утечку памяти, но так как он заявляет, что позже видит, что удаление названо. "Позже однако память освобождена с помощью удалить вызова":

Кроме того, моя причина ответа, как я сделал, происходила из-за комментария OP "структуры переменной длины (TAPI), где размер структуры будет зависеть от строк переменной длины"

Тот комментарий казался, что он подвергал сомнению динамический характер выделений против заставляемого броска и последовательно задавался вопросом, вызовет ли это утечку памяти. Я читал между строк, если Вы будете ;).

0
ответ дан 3 December 2019 в 13:37
поделиться

Len: проблема с этим состоит в том, что pStruct является СТРУКТУРА*, но выделенной памятью является на самом деле БАЙТ [] некоторого неизвестного размера. Поэтому удалите [] pStruct, не освободит всю выделенную память.

0
ответ дан 3 December 2019 в 13:37
поделиться

Да, который может, начиная с Вашего выделения с новым [], но освобождение с delelte, да malloc/free более безопасен здесь, но в C++ Вы не должны использовать их, так как они не обработают (de) конструкторов.

Также Ваш код назовет deconstructor, но не конструктора. Для некоторых структур это может вызвать утечку памяти (если конструктор выделил дальнейшую память, например, для строки),

Лучше должен был бы сделать это правильно, как это также правильно вызовет любых конструкторов и deconstructors

STRUCT* pStruct = new STRUCT;
...
delete pStruct;
0
ответ дан 3 December 2019 в 13:37
поделиться

Это - массив, удаляют ([]), Вы обращаетесь к, не, вектор удаляет. Вектор является станд.:: вектор, и это заботится об удалении своих элементов.

1
ответ дан 3 December 2019 в 13:37
поделиться

Всегда лучше сохранить приобретение/выпуск любого ресурса максимально сбалансированным. Хотя утечку или не трудно сказать в этом случае. Это зависит от реализации компилятора вектора (de) выделение.

BYTE * pBytes = new BYTE [sizeof(STRUCT) + nPaddingSize];

STRUCT* pStruct = reinterpret_cast< STRUCT* > ( pBytes ) ;

 // do stuff with pStruct

delete [] pBytes ;
0
ответ дан 3 December 2019 в 13:37
поделиться

Я в настоящее время не могу голосовать, но ответ slicedlime предпочтителен для ответа Rob Walker, так как проблема не имеет никакого отношения к средствам выделения или имеет ли СТРУКТУРА деструктор.

Также обратите внимание, что пример кода не обязательно приводит к утечке памяти - это - неопределенное поведение. В значительной степени что-либо могло произойти (ни от чего плохо к катастрофическому отказу далеко, далеко).

Пример кода приводит к неопределенному поведению, простому и простому. ответ slicedlime является прямым и к точке (с протестом, что слово 'вектор' должно быть изменено для 'выстраивания', так как векторы являются вещью STL).

Этот вид материала покрыт вполне прилично в FAQ C++ (Разделы 16.12, 16.13, и 16.14):

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.12

1
ответ дан 3 December 2019 в 13:37
поделиться

Если действительно необходимо сделать этот вид вещи, необходимо, вероятно, назвать оператор new непосредственно:

STRUCT* pStruct = operator new(sizeof(STRUCT) + nPaddingSize);

Я верю вызову его, этот путь старается не вызывать конструкторов/деструкторы.

2
ответ дан 3 December 2019 в 13:37
поделиться

Как выделено в других сообщениях:

1) Вызовы к новому/удаляет выделяют память и могут вызвать конструкторов/деструкторы (C++ '03 5.3.4/5.3.5)

2) Смешивание array/non-array версии new и delete неопределенное поведение. (C++ '03 5.3.5/4)

Рассмотрение источника, кажется, что кто-то сделал поиск и заменять для malloc и free и вышеупомянутое является результатом. C++ действительно имеет прямую замену для этих функций, и это должно вызвать функции выделения для new и delete непосредственно:

STRUCT* pStruct = (STRUCT*)::operator new (sizeof(STRUCT) + nPaddingSize);
// ...
pStruct->~STRUCT ();  // Call STRUCT destructor
::operator delete (pStruct);

Если конструктора для СТРУКТУРЫ нужно вызвать, то Вы могли рассмотреть выделение памяти и затем использовать размещение new:

BYTE * pByteData = new BYTE[sizeof(STRUCT) + nPaddingSize];
STRUCT * pStruct = new (pByteData) STRUCT ();
// ...
pStruct->~STRUCT ();
delete[] pByteData;
3
ответ дан 3 December 2019 в 13:37
поделиться

@eric - Спасибо за комментарии. Вы продолжаете говорить что-то, хотя, который сводит меня с ума:

Те библиотеки времени выполнения обрабатывают вызовы управления памятью к ОС в независимом от операционной системы непротиворечивом синтаксисе, и те библиотеки времени выполнения ответственны за то, что последовательно делали malloc и новую работу между Ose, такими как Linux, Windows, Солярис, AIX, и т.д....

Это не верно. Разработчик компилятора обеспечивает реализацию библиотек станд., например, и они абсолютно свободны реализовать библиотеки зависимым от операционной системы способом. Они свободны, например, выполнить один гигантский вызов к malloc, и затем управлять памятью в блоке однако они желают.

Совместимость обеспечивается, потому что API станд., и т.д. то же - не потому что библиотеки времени выполнения все оборачиваются и называют те же самые вызовы ОС.

2
ответ дан 3 December 2019 в 13:37
поделиться

В стандарте C++ ясно говорится:

delete-expression:
             ::opt delete cast-expression
             ::opt delete [ ] cast-expression

Первая альтернатива для объектов немассива, и второе для массивов. Операнд должен иметь тип указателя или тип класса, имеющий функцию однократного преобразования (12.3.2) к типу указателя. Результат имеет тип пусто.

В первой альтернативе (удаляют объект), значение операнда удаляет, будет указатель на объект немассива [...] В противном случае поведение не определено.

Значение операнда в delete pStruct указатель на массив char, независимый от его статического типа (STRUCT*). Поэтому любое обсуждение утечек памяти довольно бессмысленно, потому что код плохо формируется, и компилятор C++ не требуется, чтобы производить разумный исполняемый файл в этом случае.

Это могло пропустить память, это не могло, или это могло сделать что-либо до катастрофического отказа Вашей системы. Действительно, реализация C++, с которой я протестировал Ваш код, прерывает выполнение программы при удалить выражении.

4
ответ дан 3 December 2019 в 13:37
поделиться

Поведение кода не определено. Можно быть удачливыми (или не), и это может работать с компилятором, но действительно это не правильный код. Существует две проблемы с ним:

  1. delete должен быть массив delete [].
  2. delete должен быть назван на указателе на тот же тип как выделенный тип.

Таким образом, чтобы быть совершенно корректными, Вы хотите сделать что-то вроде этого:

delete [] (BYTE*)(pStruct);
6
ответ дан 3 December 2019 в 13:37
поделиться

Различные возможные применения новых ключевых слов и удаляют, кажется, создают изрядное количество беспорядка. Всегда существует два этапа к построению динамических объектов в C++: выделение необработанной памяти и конструкция нового объекта в выделенной области памяти. С другой стороны объектного времени жизни существует разрушение объекта и освобождение ячейки памяти, где объект находился.

Часто эти два шага выполняются единственным оператором C++.

MyObject* ObjPtr = new MyObject;

//...

delete MyObject;

Вместо вышеупомянутого можно использовать функции выделения памяти сырых данных C++ operator new и operator delete и явная конструкция (через размещение new) и разрушение для выполнения эквивалентных шагов.

void* MemoryPtr = ::operator new( sizeof(MyObject) );
MyObject* ObjPtr = new (MemoryPtr) MyObject;

// ...

ObjPtr->~MyObject();
::operator delete( MemoryPtr );

Заметьте, как нет никакого кастинга, включенного, и только один тип объекта создается в выделенной области памяти. Используя что-то как new char[N] поскольку способ выделить необработанную память является технически неправильным как, логически, char объекты создаются в недавно выделенной памяти. Я не знаю ни о какой ситуации, где она 'просто не работает', но она размывает различие между необработанным выделением памяти и созданием объекта, таким образом, я отговариваю от нее.

В данном случае нет никакого усиления, которое будет иметься путем выделения двух шагов delete но действительно необходимо вручную управлять начальным выделением. Вышеупомянутый код работает в 'все рабочий' сценарий, но он пропустит необработанную память в случае где конструктор MyObject выдает исключение. В то время как это могло быть поймано и решено с обработчиком исключений при выделении, это, вероятно, более опрятно для обеспечения пользовательского оператора, нового так, чтобы полная конструкция могла быть обработана размещением новое выражение.

class MyObject
{
    void* operator new( std::size_t rqsize, std::size_t padding )
    {
        return ::operator new( rqsize + padding );
    }

    // Usual (non-placement) delete
    // We need to define this as our placement operator delete
    // function happens to have one of the allowed signatures for
    // a non-placement operator delete
    void operator delete( void* p )
    {
        ::operator delete( p );
    }

    // Placement operator delete
    void operator delete( void* p, std::size_t )
    {
        ::operator delete( p );
    }
};

Здесь существует несколько тонких моментов. Мы определяем размещение класса, новое так, чтобы мы могли выделить достаточно памяти для экземпляра класса плюс некоторый пользователь specifiable дополнение. Поскольку мы делаем это, мы должны обеспечить, размещение соответствия удаляют так, чтобы, если выделение памяти успешно выполняется, но сбои конструкции, выделенная память автоматически освобождена. К сожалению, подпись для нашего размещения удаляют соответствия, которые одна из двух позволенных подписей для неразмещения удаляет так, мы должны обеспечить, другая форма неразмещения удаляют так, чтобы наше реальное размещение удалило, рассматривается как размещение, удаляют. (Мы могли иметь вокруг этого путем добавления, что дополнительный фиктивный параметр и к нашему новому размещению и к размещению удаляет, но это потребовало бы дополнительной работы над всеми сайтами вызова.)

// Called in one step like so:
MyObject* ObjectPtr = new (padding) MyObject;

Используя единственное новое выражение нам теперь гарантируют, та память не просочится, если какая-либо часть нового выражения бросит.

В другом конце объектного времени жизни, потому что мы определили оператор, удаляют (даже если мы не имели, память для объекта первоначально прибыла из глобального оператора, нового в любом случае), следующее является корректным способом уничтожить динамично созданный объект.

delete ObjectPtr;

Сводка!

  1. Не посмотрите никакие составы исполнителей! operator new и operator delete соглашение с необработанной памятью, новое размещение может создать объекты в необработанной памяти. Явный бросок от a void* к объектному указателю обычно знак чего-то логически неправильно, даже если он действительно 'просто работает'.

  2. Мы полностью проигнорировали новый [] и удаляем []. Эти переменные объекты размера не будут работать в массивах в любом случае.

  3. Новое размещение позволяет новому выражению не протекать, новое выражение все еще оценивает к указателю на объект, которому нужны уничтожение и память, которой нужно освобождение. Использование некоторого типа интеллектуального указателя может помочь предотвратить другие типы утечки. Зато мы позволили плоскости delete будьте корректным способом сделать это так будет работать, большинство стандартных интеллектуальных указателей.

2
ответ дан 3 December 2019 в 13:37
поделиться

Да это вызовет утечку памяти.

Посмотрите это кроме от Глюков C++: http://www.informit.com/articles/article.aspx?p=30642, для почему.

У Raymond Chen есть объяснение как векторный new и delete отличайтесь от скалярных версий под прикрытиями для компилятора Microsoft... Здесь: http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx

По моему скромному мнению, необходимо прикрепить удаление к:

delete [] pStruct;

вместо того, чтобы переключаться на malloc/free, если только потому, что это - более простое изменение для создания, не делая ошибки ;)

И, конечно, более простое для внесения изменения, которое я показываю выше, происходит неправильно из-за кастинга в исходном выделении, это должно быть

delete [] reinterpret_cast<BYTE *>(pStruct);

таким образом я предполагаю, что это, вероятно, как легкое переключиться на malloc/free в конце концов, ;)

6
ответ дан 3 December 2019 в 13:37
поделиться

Я лично думаю, что Вы были бы более обеспеченным использованием std::vector управлять Вашей памятью, таким образом, Вам не нужно delete.

std::vector<BYTE> backing(sizeof(STRUCT) + nPaddingSize);
STRUCT* pStruct = (STRUCT*)(&backing[0]);

После того как отступающие листы определяют объем, Ваш pStruct больше не действительно.

Или, можно использовать:

boost::scoped_array<BYTE> backing(new BYTE[sizeof(STRUCT) + nPaddingSize]);
STRUCT* pStruct = (STRUCT*)backing.get();

Или boost::shared_array если необходимо переместить владение.

7
ответ дан 3 December 2019 в 13:37
поделиться

Вы были бы, мог вспомнить БАЙТ * и удаление:

delete[] (BYTE*)pStruct;
0
ответ дан 3 December 2019 в 13:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: