Je passe en revue le code C ++ de quelqu'un d'autre pour notre projet qui utilise MPI pour le calcul haute performance (10 ^ 5 - 10 ^ 6 cœurs). Le code est destiné à permettre des communications entre (potentiellement) différentes machines sur différentes architectures. Il a écrit un commentaire qui dit quelque chose du genre:
Nous utiliserions normalement
new
etdelete
, mais ici, j'utilisemalloc
etfree
. Cela est nécessaire car certains compilateurs rempliront les données différemment lorsqu'ilsnew
sont utilisés, ce qui entraîne des erreurs de transfert de données entre différentes plates-formes. Cela n'arrive pas avecmalloc
.
Cela ne correspond à rien de ce que je sais des questions standard par new
rapport aux malloc
questions.
Quelle est la différence entre new / delete et malloc / free? fait allusion à l'idée que le compilateur pourrait calculer la taille d'un objet différemment (mais alors pourquoi est-ce différent de l'utilisation sizeof
?).
malloc & placement nouveau vs nouveau est une question assez populaire, mais ne parle que de l' new
utilisation de constructeurs là où ce malloc
n'est pas le cas, ce qui n'est pas pertinent pour cela.
comment malloc comprend-il l'alignement? dit que la mémoire est garantie d'être correctement alignée avec l'un new
ou l' autre ou malloc
ce que je pensais auparavant.
Je suppose qu'il a mal diagnostiqué son propre bug quelque temps dans le passé et en a déduit new
et a malloc
donné différentes quantités de rembourrage, ce qui n'est probablement pas vrai. Mais je ne trouve pas la réponse avec Google ou dans aucune question précédente.
Aidez-moi, StackOverflow, vous êtes mon seul espoir!
la source
malloc
etnew
, commenew
dans certains environnements, allouer un bloc, ajoute des données au début et renvoie un pointeur vers un emplacement juste après ces données. (Je suis d'accord avec les autres, à l'intérieur du bloc de données,malloc
et jenew
dois utiliser le même type de rembourrage.)Réponses:
IIRC, il y a un point difficile.
malloc
est garanti de renvoyer une adresse alignée pour tout type standard.::operator new(n)
est uniquement garanti de renvoyer une adresse alignée pour tout type standard ne dépassant pas n , et si ceT
n'est pas un type de caractère, alors ilnew T[n]
est seulement nécessaire de renvoyer une adresse alignée pourT
.Mais cela n'est pertinent que lorsque vous jouez à des astuces spécifiques à l'implémentation, comme utiliser les quelques bits inférieurs d'un pointeur pour stocker des indicateurs, ou si vous comptez sur l'adresse pour avoir plus d'alignement que ce dont elle a strictement besoin.
Cela n'affecte pas le remplissage dans l'objet, qui a nécessairement exactement la même disposition, quelle que soit la façon dont vous avez alloué la mémoire qu'il occupe. Il est donc difficile de voir comment la différence pourrait entraîner des erreurs de transfert de données.
Y a-t-il un signe de ce que l'auteur de ce commentaire pense des objets sur la pile ou dans les globaux, qu'ils soient à son avis "rembourrés comme du malloc" ou "rembourrés comme neufs"? Cela pourrait donner des indices sur l'origine de l'idée.
Peut-être qu'il est confus, mais peut - être le code dont il parle est plus qu'une différence entre droite
malloc(sizeof(Foo) * n)
vsnew Foo[n]
. Peut-être que c'est plus comme:contre.
Autrement dit, il dit peut-être "J'utilise malloc", mais signifie "Je compresse manuellement les données dans des emplacements non alignés au lieu d'utiliser une structure". En fait, ce
malloc
n'est pas nécessaire pour emballer manuellement la structure, mais ne pas s'en rendre compte est un moindre degré de confusion. Il est nécessaire de définir la disposition des données envoyées sur le fil. Différentes implémentations rempliront les données différemment lorsque la structure est utilisée.la source
char
tableaux ne sont jamais bourrés du tout, donc je m'en tiendrai à "confused" comme explication.Votre collègue a peut-être
new[]/delete[]
pensé au cookie magique (ce sont les informations que l'implémentation utilise lors de la suppression d'un tableau). Cependant, cela n'aurait pas posé de problème si l'allocation commençant à l'adresse renvoyée parnew[]
était utilisée (par opposition à celle de l'allocateur).L'emballage semble plus probable. Les variations dans les ABI pourraient (par exemple) entraîner un nombre différent d'octets de fin ajoutés à la fin d'une structure (ceci est influencé par l'alignement, considérez également les tableaux). Avec malloc, la position d'une structure pourrait être spécifiée et donc plus facilement transférable à un ABI étranger. Ces variations sont normalement évitées en spécifiant l'alignement et le tassement des structures de transfert.
la source
La disposition d'un objet ne peut pas dépendre du fait qu'il a été alloué à l'aide de
malloc
ounew
. Ils renvoient tous les deux le même type de pointeur, et lorsque vous passez ce pointeur à d'autres fonctions, ils ne sauront pas comment l'objet a été alloué.sizeof *ptr
dépend simplement de la déclarationptr
, et non de la manière dont il a été attribué.la source
Je pense que tu as raison. Le remplissage est effectué par le compilateur non
new
oumalloc
. Les considérations de remplissage s'appliqueraient même si vous déclariez un tableau ou une structure sans utilisernew
ou pasmalloc
du tout. Dans tous les cas, bien que je puisse voir comment différentes implémentations denew
etmalloc
pourraient causer des problèmes lors du portage de code entre plates-formes, je ne vois absolument pas comment elles pourraient causer des problèmes de transfert de données entre plates-formes.la source
new
comme un bon emballage pour,malloc
mais il semble que d'autres réponses ne soient pas tout à fait vraies. Le consensus semble être que le rembourrage devrait être le même avec l'un ou l'autre; Je pense que le problème du transfert de données entre plates-formes ne survient que si votre mécanisme de transfert est défectueux :)Lorsque je veux contrôler la disposition de ma structure de données ancienne, avec les compilateurs MS Visual que j'utilise
#pragma pack(1)
. Je suppose qu'une telle directive de précompilateur est prise en charge pour la plupart des compilateurs, comme par exemple gcc .Ceci a pour conséquence d'aligner tous les champs des structures les uns derrière les autres, sans espaces vides.
Si la plate-forme à l'autre extrémité fait de même (c'est-à-dire a compilé sa structure d'échange de données avec un remplissage de 1), alors les données récupérées des deux côtés conviennent parfaitement. Ainsi je n'ai jamais eu à jouer avec malloc en C ++.
Au pire, j'aurais envisagé de surcharger le nouvel opérateur afin qu'il effectue des choses délicates, plutôt que d'utiliser malloc directement en C ++.
la source
pragma pack
ou similaires? Je sais que cela ne fera pas partie de la norme.C'est ma supposition sauvage d'où vient cette chose. Comme vous l'avez mentionné, le problème vient de la transmission de données via MPI.
Personnellement, pour mes structures de données complexes que je veux envoyer / recevoir via MPI, j'implémente toujours des méthodes de sérialisation / désérialisation qui emballent / décompressent le tout dans / à partir d'un tableau de caractères. Maintenant, en raison du remplissage, nous savons que cette taille de la structure pourrait être plus grande que la taille de ses membres et il faut donc également calculer la taille non rembourrée de la structure de données afin de savoir combien d'octets sont envoyés / reçus.
Par exemple, si vous souhaitez envoyer / recevoir
std::vector<Foo> A
via MPI avec ladite technique, il est faux de supposer que la taille du tableau de caractères résultant estA.size()*sizeof(Foo)
en général. En d'autres termes, chaque classe qui implémente des méthodes de sérialisation / désérialisation, doit également implémenter une méthode qui rapporte la taille du tableau (ou mieux encore stocker le tableau dans un conteneur). Cela pourrait devenir la raison d'un bug. D'une manière ou d'une autre, cependant, cela n'a rien à voir avecnew
vsmalloc
comme indiqué dans ce fil.la source
En c ++: le
new
mot clé est utilisé pour allouer des octets de mémoire particuliers par rapport à une structure de données. Par exemple, vous avez défini une classe ou une structure et vous souhaitez allouer de la mémoire à son objet.ou
Mais dans tous les cas, vous avez besoin du type de données défini (class, struct, union, int, char etc ...) et seuls les octets de mémoire seront alloués, ce qui est nécessaire pour son objet / variable. (c'est-à-dire des multiples de ce type de données).
Mais dans le cas de la méthode malloc (), vous pouvez allouer n'importe quel octet de mémoire et vous n'avez pas besoin de spécifier le type de données à tout moment. Ici vous pouvez l'observer dans quelques possibilités de malloc ():
ou
ou
la source
malloc est un type de fonction et new est un type de type de données en c ++ en c ++, si nous utilisons malloc que nous devons et devrions utiliser typecast sinon le compilateur vous donnera une erreur et si nous utilisons un nouveau type de données pour l'allocation de mémoire que nous n'avons pas besoin pour typer
la source