Страницы

Поиск по вопросам

среда, 18 декабря 2019 г.

Как правильно обнулить память?

#cpp #winapi


Собственно очень интересует вопрос, если например массив нужно "обнулить", "очистить",
не знаю как правильно выразится, чтобы туда не попал "мусор", нужно это делать мемсетом
или можно заполнить массив нулями просто и это будет одно и тоже "{ 0 }", хотелось
бы выслушать мнение людей с большим "опытом работы" в программировании, есть ли разница
и может ли это повлечь какие-то проблемы в больших проектах(программах) или может это
нужно делать как-то по другому?

 OPENFILENAME ofn = { 0 };
ZeroMemory(&ofn, sizeof(ofn));


или

char FileName[260];
ZeroMemory(&FileName, sizeof(FileName));

    


Ответы

Ответ 1



Для начала, локальные переменные необходимо инициализировать до первого чтения. Чтение неинициализтрованной переменной — очень серьёзная ошибка программиста, и может привести, например, к вылету программы. (Почитайте про undefined behaviour.) Затем, код наподобие OPENFILENAME ofn = { 0 }; уже есть инициализация, дополнительное «обнуление памяти» не нужно. (В современных версиях C++ обычно достаточно просто OPENFILENAME ofn = {};.) В случае, когда вы объявляете массив, проще опять-таки попросить об инициализации компилятор (char FileName[260] = {};), чем обнулять массив вручную (ZeroMemory). Другое дело, если вы хотите инициализировать массив ненулевым значением, это придётся делать вручную. Для «единичных» структур обычно можно всё ещё применять инициализацию: MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; Если вы собираетесь сразу же записывать данные в вашу структуру/массив, инициализация не имеет особого смысла. (Хотя хороший оптимизатор может увидеть это и выкинуть её.) Если вы собираетесь заполнять массив значениями, не имеет смысла перед этим прописывать всё нулями. Однако, если вы передаёте структуру/массив в чужую функцию, имеет смысл заранее посмотреть в документацию, читает функция эту структуру данных, или лишь заполняет её. Если вы твёрдо уверены, что функция лишь заполняет вашу структуру, можно пропустить инициализацию.

Ответ 2



Есть ли разница между memset и ZeroMemory? Нет, фактически её нет — поэтому, если нужно обнулить уже существующие данные, то можно использовать и то и другое. Но у этих функций есть одна неприятная особенность — компилятор может их выкинуть, если считает, что после обнуление, память не будет более использоваться. Это нормально, в большинстве случаев. Но очень часто обнуление памяти используется для того, чтобы очистить какой-то секрет(пароль или ещё что-то), вот тогда это становится проблемой — компилятор выкидывает вызов и секрет продолжает висеть в памяти, доступный для всех. Поэтому, когда память, занимаемая секретом, очищается, нужно использовать функцию SecureZeroMemory — эта функцию гарантировано обнулит массив в памяти.

Ответ 3



Для инициализации массива на стеке нулями достаточно написать так: int arr[size] = {};

Ответ 4



В общем случае значение переменной, равное 0, не обязательно означает, что вся память, занятая этой переменной, заполняется нулями. Поэтому, строго говоря, конструкция memset(a, 0, sizeof(a)); не обязательно эквивалентна конструкции for (int i = 0; (i < N); ++i) a[i] = 0; Однако, для POD-типов, обычно эти конструкции означают одно и то же (мне лично другого не встречалось). Но для определяемых пользователем типов (классов) говорить о такой эквивалентности уже нельзя. Поэтому в C++ для классов лучше использовать операторы присваивания, а для массивов - библиотечный алгоритм fill (или fill_n начиная с C++11).

Комментариев нет:

Отправить комментарий