Je travaille sur le morceau de code ci-dessous et quand std::bad_alloc
ce code, std::bad_alloc
exception std::bad_alloc
:
int _tmain(int argc, _TCHAR* argv[]) { FILE * pFile; size_t state; pFile = fopen("C:\\shared.tmp", "rb"); if (pFile != NULL) { size_t rt = fread(&state, sizeof(int), 1, pFile); char *ssortingng = NULL; ssortingng= new char[state + 1]; fclose(pFile); } return 0; }
Cette ligne ci-dessous provoque une exception:
ssortingng = new char[state + 1];
Pourquoi cela se produit et comment puis-je résoudre ce problème?
Vous passez l’adresse d’une variable non initialisée de 64 bits (8 octets, sur les systèmes 64 bits modernes), et dites à fread
de lire sizeof(int)
(32 bits, 4 octets sur ces mêmes systèmes) octets de la fichier dans cette variable.
Cela écrasera 4 octets de la variable avec la valeur lue, mais laissera les 4 autres non initialisés. Les 4 octets qu’il écrase dépendent de l’architecture (le moins significatif sur les processeurs Intel, le plus significatif sur les ARM configurés en mode big endian), mais le résultat sera probablement anormal, car 4 octets n’ont pas été initialisés et peuvent contenir quelque chose .
Dans votre cas, il s’agit très probablement des octets les plus significatifs et contiennent au moins un bit non nul, ce qui signifie que vous essayez d’allouer bien au-delà de 4 Go de mémoire, ce que vous n’avez pas.
La solution est de rendre l’ state
std::uint32_t
(puisque vous vous attendez à ce que le fichier contienne 4 octets représentant un entier non signé; n’oubliez pas d’inclure
) et passez sizeof(std::uint32_t)
, et en général Assurez-vous que pour chaque appel de même type, lorsque vous passez un pointeur et une taille, assurez-vous que la taille du pointeur correspond exactement à celle que vous passez. Passer un size_t*
et sizeof(int)
ne répond pas à ces exigences sur les systèmes 64 bits, et comme la taille des types de base de C ++ n’est pas garantie, vous ne voulez généralement pas les utiliser pour les E / S binarys.
Il y a plusieurs choses que vous pouvez améliorer dans votre code C ++, mais il y a plusieurs raisons pour lesquelles vous vous retrouvez avec ce comportement:
Tout d’abord, l’ state
la variable est de type size_t
, mais votre code tente d’initialiser sa valeur à l’aide de fread(&state, sizeof(int), 1, pFile);
. Maintenant, si sizeof(state) != sizeof(int)
vous avez un comportement indéfini. Si sizeof(state) < sizeof(int)
, alors l'instruction fread
écrase généralement de la mémoire arbitraire après le stockage pour l' state
variable. Cela conduit à un comportement indéfini (par exemple, l' state
peut avoir une grande valeur aléatoire et l'atsortingbution échoue).
Deuxièmement, si sizeof(state) > sizeof(int)
, l' state
n'est que partiellement initialisé et sa valeur réelle dépend à la fois des bits initialisés (par fread
) et non initialisés. Sa valeur peut donc être un grand nombre et l’allocation peut échouer.
Troisièmement, le if sizeof(state) == sizeof(int)
alors il se peut que la valeur lue soit trop grande et que l'allocation échoue simplement parce que vous manquez de mémoire.
Quasortingèmement, la valeur que vous lisez dans le fichier peut avoir un codage ou une endianness différent. Par exemple, si la valeur a été écrite dans le fichier au format big-endian, mais est fread
sur un processeur peu endian, les octets risquent d'être mal échangés. Vous devrez peut-être échanger les octets avant d'utiliser la valeur lue.
Je vous suggère d’utiliser à la place un type entier à largeur fixe de
(ou
pour pré-C ++ 11), tel que std::uint64_t
pour l’ state
variable, lire la valeur avec fread(&state, sizeof(state), 1, pFile);
, puis état d'octet-swap si la qualité de votre CPU ne correspond pas à la valeur de la valeur stockée dans le fichier.
Vous devez décider du nombre maximum de caractères que vous souhaitez atsortingbuer et de la sortie d’erreur si l’ state
est supérieur à celui-ci. Presque certainement, c’est le cas.