Я просматриваю чужой код C ++ для нашего проекта, который использует MPI для высокопроизводительных вычислений (10 ^ 5 - 10 ^ 6 ядер). Код предназначен для обеспечения связи между (потенциально) разными машинами на разных архитектурах. Он написал комментарий, в котором говорится примерно следующее:
Обычно мы использовали бы
new
иdelete
, но здесь я используюmalloc
иfree
. Это необходимо, потому что некоторые компиляторы по-разному дополняют данные приnew
использовании, что приводит к ошибкам при передаче данных между разными платформами. Этого не происходит сmalloc
.
Это не вписывается ни с чем я знаю от стандартных new
против malloc
вопросов.
В чем разница между new / delete и malloc / free? намекает на идею, что компилятор может вычислять размер объекта по-другому (но тогда почему это отличается от использования sizeof
?).
malloc и размещение new vs. new - довольно популярный вопрос, но он говорит только об new
использовании конструкторов там, где malloc
нет, что не имеет отношения к этому.
как malloc понимает выравнивание? говорит, что память гарантированно будет правильно выровнена с любым new
или, malloc
как я раньше думал.
Я предполагаю, что когда-то в прошлом он неправильно диагностировал свою собственную ошибку, вывел ее new
и malloc
дал разное количество отступов, что, по-моему, вероятно, неверно. Но я не могу найти ответ ни в Google, ни в каком-либо предыдущем вопросе.
Помогите мне, StackOverflow, ты моя единственная надежда!
источник
malloc
иnew
, посколькуnew
в некоторых средах выделяют блок, добавляют некоторые данные в начало и возвращают указатель на местоположение сразу после этих данных. (Я согласен с другими, внутри блока данныхmalloc
иnew
должен использовать такие же отступы.)Ответы:
IIRC есть один придирчивый момент.
malloc
гарантированно вернет адрес, выровненный для любого стандартного типа.::operator new(n)
гарантированно возвращает только адрес, выровненный для любого стандартного типа не больше n , а еслиT
не является символьным типом, тоnew T[n]
требуется только вернуть адрес, выровненный дляT
.Но это актуально только тогда, когда вы играете уловки, зависящие от реализации, например, используете несколько нижних битов указателя для хранения флагов или иным образом полагаетесь на то, что адрес имеет большее выравнивание, чем это строго необходимо.
Это не влияет на заполнение внутри объекта, который обязательно имеет точно такой же макет, независимо от того, как вы распределили память, которую он занимает. Так что сложно понять, как разница может привести к ошибкам при передаче данных.
Есть ли какие-либо признаки того, что автор этого комментария думает об объектах в стеке или глобальных объектах, независимо от того, являются ли они, по его мнению, «дополненными как malloc» или «дополненными как новые»? Это может дать ключ к разгадке того, откуда пришла идея.
Может быть , он смущен, но , возможно, код он о разговоре больше , чем разница между прямой
malloc(sizeof(Foo) * n)
противnew Foo[n]
. Может, это больше похоже на:vs.
То есть, возможно, он говорит : «Я использую malloc», но означает: «Я вручную упаковываю данные в невыровненные места вместо использования структуры». На самом деле
malloc
не требуется для того, чтобы вручную упаковать структуру, но если вы не осознаете это, то это меньшая степень путаницы. Необходимо определить структуру данных, передаваемых по сети. Различные реализации будут подушечка данные по- разному , когда структура используется.источник
char
массивы вообще никогда не дополняются, поэтому я буду придерживаться слова «запутанный» в качестве объяснения.Ваш коллега, возможно, имел
new[]/delete[]
в виду волшебный файл cookie (это информация, которую реализация использует при удалении массива). Однако это не было бы проблемой, если бы использовалось выделение, начинающееся с адреса, возвращенногоnew[]
функцией (в отличие от распределителя).Упаковка кажется более вероятной. Вариации в ABI могут (например) привести к другому количеству завершающих байтов, добавленных в конце структуры (на это влияет выравнивание, также учитывайте массивы). С помощью malloc можно указать положение структуры и, таким образом, упростить перенос ее в чужой ABI. Эти отклонения обычно предотвращаются путем задания выравнивания и упаковки структур переноса.
источник
Макет объекта не может зависеть от того, был ли он выделен с помощью
malloc
илиnew
. Оба они возвращают один и тот же тип указателя, и когда вы передаете этот указатель другим функциям, они не узнают, как был выделен объект.sizeof *ptr
просто зависит от объявленияptr
, а не от того , как он был назначен.источник
Я думаю, вы правы. Заполнение выполняется компилятором, а не
new
илиmalloc
. Замечания по заполнению будут применяться, даже если вы объявили массив или структуру без использованияnew
илиmalloc
вообще. В любом случае, хотя я вижу, как разные реализацииnew
иmalloc
могут вызывать проблемы при переносе кода между платформами, я совершенно не понимаю, как они могут вызывать проблемы при передаче данных между платформами.источник
new
как хорошую оболочку,malloc
но из других ответов кажется, что это не совсем так. Кажется, что консенсус заключается в том, что заполнение должно быть одинаковым с любым из них; Я думаю, что проблема с передачей данных между платформами возникает только в том случае, если ваш механизм передачиКогда я хочу управлять компоновкой моей простой старой структуры данных, я использую компиляторы MS Visual
#pragma pack(1)
. Я полагаю, что такая директива прекомпилятора поддерживается большинством компиляторов, например, gcc .Следствием этого является выравнивание всех полей структур одно за другим без пустых пространств.
Если платформа на другом конце делает то же самое (т. Е. Скомпилировала свою структуру обмена данными с заполнением 1), то данные, полученные с обеих сторон, подходят. Таким образом, мне никогда не приходилось играть с malloc в C ++.
В худшем случае я бы подумал о перегрузке оператора new, чтобы он выполнял некоторые хитрые вещи, вместо того, чтобы использовать malloc непосредственно в C ++.
источник
pragma pack
или подобных? Я понимаю, что это не будет частью стандарта.Это мое безумное предположение о том, откуда эта штука. Как вы упомянули, проблема связана с передачей данных по MPI.
Лично для моих сложных структур данных, которые я хочу отправлять / получать через MPI, я всегда реализую методы сериализации / десериализации, которые упаковывают / распаковывают все это в / из массива символов. Теперь, благодаря заполнению, мы знаем, что этот размер структуры может быть больше, чем размер ее членов, и, следовательно, также необходимо вычислить незаполненный размер структуры данных, чтобы мы знали, сколько байтов отправлено / получено.
Например, если вы хотите отправлять / получать
std::vector<Foo> A
через MPI с помощью указанной техники, неверно предполагать, что размер результирующего массива символовA.size()*sizeof(Foo)
в целом. Другими словами, каждый класс, реализующий методы сериализации / десериализации, также должен реализовывать метод, который сообщает размер массива (или, еще лучше, сохраняет массив в контейнере). Это могло стать причиной ошибки. Так или иначе, однако, это не имеет ничего общего сnew
vs,malloc
как указано в этой ветке.источник
В c ++:
new
ключевое слово используется для выделения определенных байтов памяти по отношению к некоторой структуре данных. Например, вы определили некоторый класс или структуру и хотите выделить память для этого объекта.или
Но во всех случаях вам нужен определенный тип данных (класс, структура, объединение, int, char и т. Д.), И будут выделены только те байты памяти, которые необходимы для его объекта / переменной. (т. е. кратные этому типу данных).
Но в случае метода malloc () вы можете выделить любые байты памяти, и вам не нужно постоянно указывать тип данных. Здесь вы можете увидеть это в нескольких возможностях malloc ():
или
или
источник
malloc - это тип функции, а new - это тип типа данных в c ++ в c ++, если мы используем malloc, чем должны, и должны использовать приведение типов, иначе компилятор выдаст вам ошибку, и если мы используем новый тип данных для выделения памяти, чем нам не нужно приводить к типу
источник