Я новичок, когда дело доходит до управления памятью в C ++. Я читал, что если вы создаете класс с new
ключевое слово, которое вы должны delete
объект, чтобы освободить свою память. Я также читал, что примитивные типы, такие как int
, char
а также bool
, создаются в стеке, что означает, что они удаляются при выходе из области видимости.
Но как насчет примитивных типов, созданных с new
ключевое слово? Нужно ли явно звонить delete
? Они созданы в куче как классы? Или, поскольку они примитивны, они все еще создаются в стеке?
Я спрашиваю, потому что я выделяю LPTSTR
используя новое ключевое слово, но я беспокоюсь, что если я не позвоню delete
что память никогда не будет освобождена. Вот мой код с голым вопросом в комментариях:
#include <Windows.h>
#include <tchar.h>
#include <string>
#ifdef _UNICODE
typedef std::wstring Str;
#else // ANSI
typedef std::string Str;
#endif
Str GetWndStr(HWND hwnd) {
const int length = GetWindowTextLength(hwnd);
if (length != 0) {
LPTSTR buffer = new TCHAR[length + 1]; // Allocation of string
GetWindowText(hwnd, buffer, length + 1);
Str text(buffer);
delete buffer; // <--- Is this line necessary?
return text;
} else {
return _T("");
}
}
Мне нужно позвонить delete
? Некоторое время назад я пытался использовать GlobalAlloc()
а также GlobalFree()
, но во время выполнения я получил сообщение об ошибке незаконного изменения стека, у меня нет точного сообщения об ошибке, как это было некоторое время назад. Кроме того, в дополнение к вашему ответу, если вы хотите предоставить мне ресурсы, которые вы считаете полезными, чтобы узнать больше об управлении памятью в C ++, это было бы неплохо.
Ваш массив выделен с new[]
и, следовательно, должны быть удалены с delete[]
(не delete
).
Ваше явное динамическое распределение также не нужно:
Str text(length+1, 0);
GetWindowText(hwnd, &text[0], length + 1);
text.resize(length); // remove NUL terminator
return text;
В C ++ 03 есть какое-то обоснование, string
а также wstring
фактически выделяем непрерывную память, пригодную для передачи в качестве буфера. Это не гарантируется стандартом C ++ 03, но на самом деле это верно для MSVC ++. Если вы не хотите полагаться на этот факт, то это является гарантировано для вектора, так что вы можете использовать это для буфера:
std::vector<TCHAR> buffer(length+1);
GetWindowText(hwnd, &buffer[0], length + 1);
return Str(buffer.begin(), buffer.end() - 1);
Прямое использование довольно редко new[]
в C ++. В обоих случаях мой vector
или же string
Буфер является автоматической переменной, поэтому мне не нужно делать ничего особенного, чтобы убедиться, что он уничтожен правильно, когда заканчивается его область действия.
Для каждого new
должен быть delete
и для каждого new[]
должен быть delete[]
, Обратите внимание, что память выделена с new[]
должен быть удален с delete[]
, что не так в размещенном коде.
Умный указатель может быть использован, boost::scoped_array
например, который будет выполнять delete[]
в его деструкторе (или reset()
функция). Это особенно полезно, если после вызова new[]
:
boost::scoped_array<TCHAR> buffer(new TCHAR[length + 1]);
GetWindowText(hwnd, buffer.get(), length + 1);
Str text(buffer.get()); // buffer will be deleted at end of scope.
ДА (если вы не используете умные указатели или аналогичные, чтобы удалить его для вас)
Да, правило очень простое. Все, что вы выделяете new
должен быть освобожден с delete
; и все выделено new[]
должен быть освобожден с delete[]
,
Чтобы уменьшить вероятность ошибки, лучше всего использовать контейнеры, умные указатели или другие RAII-объекты стиля для управления динамическими ресурсами, а не для использования delete
сам.
Конечно, независимо от того, какой тип был выделен. Это все еще имеет место в памяти.