Ответ 1
Выдержки из Рэймонд Чен OldNewThing
Еще во времена 16-битной Windows разница была значительной.
В 16-битной Windows доступ к памяти осуществлялся через значения, называемые "селекторами", каждое из которых могло адресовать до 64 КБ. Был селектор по умолчанию, называемый "селектор данных"; операции над так называемыми "ближними указателями" были выполнены относительно селектора данных. Например, если у вас был ближний указатель p, значение которого было 0x1234, а ваш селектор данных был 0x012F, то когда вы писали * p, вы обращались к памяти в 012F: 1234. (Когда вы объявили указатель, он был рядом по умолчанию. Вы должны были явно сказать FAR, если вы хотели дальний указатель.)
Важное замечание: Ближайшие указатели всегда относятся к селектору, обычно к селектору данных.
Функция GlobalAlloc выделяет селектор, который можно использовать для доступа к объему запрошенной вами памяти. Вы можете получить доступ к памяти в этом селекторе с помощью "дальнего указателя". "Дальний указатель" - это селектор в сочетании с ближним указателем. (Помните, что ближний указатель относительно селектора; когда вы объединяете ближний указатель с соответствующим селектором, вы получаете дальний указатель.)
Каждый экземпляр программы и DLL имеет свой собственный селектор данных, известный как HINSTANCE. Следовательно, если у вас был ближний указатель p и доступ к нему осуществлялся через * p из исполняемого файла программы, он обращался к памяти относительно экземпляров программы HINSTANCE. Если вы получили к нему доступ из DLL, у вас есть память относительно вашей DLL HINSTANCE.
Следовательно, в 16-битных Windows функции LocalAlloc и GlobalAlloc были совершенно разными! LocalAlloc вернул ближний указатель, тогда как GlobalAlloc вернул селектор.
Указатели, которые вы намеревались передавать между модулями, должны были иметь форму "дальних указателей", потому что каждый модуль имеет свой селектор по умолчанию. Если вы хотели передать право собственности на память другому модулю, вам пришлось использовать GlobalAlloc, поскольку это позволило получателю вызвать GlobalFree, чтобы освободить его.
Даже в Win32 вы должны быть осторожны, чтобы не перепутать локальную кучу с глобальной кучей. Память, выделенная от одного, не может быть освобождена от другого. Все странности в ближних и дальних указателях исчезли с переходом на Win32. Но функции локальной кучи и функции глобальной кучи, тем не менее, являются двумя различными интерфейсами кучи.
Также указанная вами ссылка ясно говорит о том, что
Начиная с 32-разрядной версии Windows, GlobalAlloc и LocalAlloc реализованы как функции-оболочки, которые вызывают HeapAlloc, используя дескриптор кучи процесса по умолчанию, и HeapAlloc может быть вызвано исключение, если память не может быть выделена, эта возможность недоступна с LocalAlloc.
Если вы не понимаете, что такое Malloc vs new, ответ Billy ONeal достаточно ясно это объясняет.
Для различия между malloc и HeapAlloc, Дэвид Хеффернан и Луис Мигель Хуапайя ответ вместе дает идеальное решение:
-
malloc
является портативным, частью стандарта.malloc
(и другие функции кучи времени выполнения C) зависят от модуля, что означает, что если вы вызываетеmalloc
в коде из одного модуля (например, DLL), то вы должны вызыватьfree
внутри кода того же модуля, иначе вы можете получить довольно плохую кучу коррупция. -
HeapAlloc
не переносим, это функция Windows API. ИспользованиеHeapAlloc
сGetProcessHeap
вместоmalloc
, включая перегрузку операторовnew
иdelete
для их использования, позволяет передавать динамически размещенные объекты между модулями и не беспокоиться о повреждении памяти, если память выделена в коде одного модуля и освобождена в коде другого модуля, как только указатель на блок памяти был передан внешнему модулю.