Malloc vs new — разные отступы

Я рассматриваю чужой код C ++ для нашего проекта, который использует MPI для высокопроизводительных вычислений (10 ^ 5 — 10 ^ 6 ядер). Код предназначен для обеспечения связи между (потенциально) разными машинами на разных архитектурах. Он написал комментарий, который говорит что-то вроде:

Мы обычно используем new а также delete, но здесь я использую malloc а также free, Это необходимо, потому что некоторые компиляторы будут дополнять данные по-разному, когда new используется, что приводит к ошибкам при передаче данных между различными платформами. Это не происходит с malloc,

Это не соответствует ни с чем, что я знаю из стандарта new против malloc вопросы.

В чем разница между new / delete и malloc / free? намекает на мысль, что компилятор может по-разному вычислять размер объекта (но тогда почему это отличается от использования sizeof?).

таНос & размещение нового против нового это довольно популярный вопрос, но говорит только о new используя конструкторы где malloc не, что не имеет отношения к этому.

как malloc понимает выравнивание? говорит, что память гарантированно будет правильно выровнена с new или же malloc это то, что я раньше думал.

Я думаю, что он когда-то в прошлом неправильно диагностировал свою собственную ошибку и пришел к выводу, что new а также malloc дать различное количество отступов, что я думаю, вероятно, не соответствует действительности. Но я не могу найти ответ с Google или в любом предыдущем вопросе.

Помоги мне, StackOverflow, ты моя единственная надежда!

108

Решение

IIRC есть одна примечательная точка. malloc гарантированно возвращает адрес, выровненный для любого стандартного типа. ::operator new(n) гарантированно вернуть адрес, выровненный для любого стандартного типа не больше чем n, и если T не тип персонажа тогда new T[n] требуется только для возврата адреса, выровненного для T,

Но это уместно только тогда, когда вы играете специфичные для реализации трюки, такие как использование нескольких нижних битов указателя для хранения флагов или иная зависимость от адреса для большего выравнивания, чем это строго необходимо.

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

Есть ли какой-либо признак того, что автор этого комментария думает об объектах в стеке или в глобалах, по его мнению, они «дополнены как malloc» или «дополнены как новые»? Это может дать понять, откуда пришла идея.

Может быть, он в замешательстве, но, возможно, код, о котором он говорит, — это не просто прямая разница между malloc(sizeof(Foo) * n) против new Foo[n], Может быть, это больше похоже на:

malloc((sizeof(int) + sizeof(char)) * n);

против

struct Foo { int a; char b; }
new Foo[n];

То есть может он поговорка «Я использую malloc», но средства «Я вручную упаковываю данные в невыровненные местоположения вместо использования структуры». На самом деле malloc не требуется для того, чтобы вручную упаковать структуру, но неспособность понять, что это меньшая степень путаницы. Необходимо определить макет данных, отправляемых по проводам. Различные реализации будут дополнять данные по-разному, когда структура используется.

25

Другие решения

Ваш коллега мог иметь new[]/delete[]Имеется в виду волшебное печенье (это информация, которую реализация использует при удалении массива). Однако это не было бы проблемой, если бы выделение начиналось с адреса, возвращенного new[] были использованы (в отличие от распределителя).

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

5

Расположение объекта не может зависеть от того, был ли он выделен с помощью malloc или же new, Они оба возвращают один и тот же тип указателя, и когда вы передадите этот указатель другим функциям, они не будут знать, как был расположен объект. sizeof *ptr просто зависит от объявления ptrне так, как было назначено.

3

Я думаю, вы правы. Заполнение выполняется компилятором, а не new или же malloc, Соображения заполнения будут применяться, даже если вы объявили массив или структуру без использования new или же malloc совсем. В любом случае, пока я вижу, как разные реализации new а также malloc Могут возникнуть проблемы при переносе кода между платформами, я совершенно не понимаю, как они могут вызвать проблемы при передаче данных между платформами.

3

Когда я хочу управлять макетом моей простой старой структуры данных, я использую компиляторы MS Visual #pragma pack(1), Я полагаю, что такая директива прекомпилятора поддерживается большинством компиляторов, как, например, НКУ.

Это приводит к выравниванию всех полей структур друг за другом, без пробелов.

Если платформа на другом конце делает то же самое (то есть компилирует свою структуру обмена данными с отступом 1), тогда данные, полученные с обеих сторон, хорошо подходят.
Таким образом, мне никогда не приходилось играть с malloc в C ++.

В худшем случае я бы подумал о перегрузке оператора new, чтобы он выполнял некоторые хитрые вещи, а не использовал malloc напрямую в C ++.

0

Это мое дикое предположение о том, откуда эта вещь. Как вы упомянули, проблема заключается в передаче данных через MPI.

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

Например, если вы хотите отправить / получить std::vector<Foo> A по сравнению с MPI с указанным методом, неправильно предполагать, что размер результирующего массива символов A.size()*sizeof(Foo) в общем. Другими словами, каждый класс, который реализует методы сериализации / десериализации, должен также реализовать метод, который сообщает размер массива (или, что еще лучше, хранить массив в контейнере). это может быть стать причиной ошибки. Однако, так или иначе, это не имеет ничего общего с new против malloc как указано в этой теме.

0

В с ++: newКлючевое слово используется для выделения определенных байтов памяти относительно некоторой структуры данных. Например, вы определили некоторый класс или структуру, и вы хотите выделить память для его объекта.

myclass *my = new myclass();

или же

int *i = new int(2);

Но во всех случаях вам нужен определенный тип данных (класс, структура, объединение, int, char и т. Д.), И будет выделено только то количество байтов памяти, которое требуется для его объекта / переменной. (то есть, кратные этому типу данных).

Но в случае метода malloc () вы можете выделить любые байты памяти, и вам не нужно всегда указывать тип данных. Здесь вы можете наблюдать это в нескольких возможностях malloc ():

void *v = malloc(23);

или же

void *x = malloc(sizeof(int) * 23);

или же

char *c = (char*)malloc(sizeof(char)*35);
0

malloc — это тип функции
и новый тип данных типа в C ++
в C ++, если мы используем malloc, мы должны и должны использовать typecast, иначе компилятор выдаст ошибку
и если мы используем новый тип данных для выделения памяти, то нам не нужно типизировать

-1
По вопросам рекламы [email protected]