Résolu Un 'new' qui retourne ZERO !!

  • Auteur de la discussion Rocky75
  • Date de début

Rocky75

Expert
Vous avez déjà vu un new qui retourne 0 alors qu'on cherche à allouer 300 octets?

Moi, j'ai eu ça et je ne comprends pas pourquoi... Je comprendrais qu'un new retourne 0 si la mémoire était saturée au point que Windows ne puisse plus allouer le bloc mémoire, mais pour 300 octets, je ne vois pas.

Quelques détails:
- J'ai démarré mon développement avec plusieurs 'new', dont 1 qui n'allouait que 3 int, du genre: myTable = new int[num];
(où num vaut 3)
Ca marchait très bien.
- J'ai ensuite enrichi mon code avec des appels à l'API Windows concernant les mixers des différents canaux sonores, des trucs des la lib WinMM.lib. C'est là que le new int[3] s'est mis à me retourner 0, à ma grande surprise.
- En revenant en arrière (sans l'appel aux fonctions multimédia de Windows), le new marchait à nouveau.

J'ai finalement contourné le problème en créant un tableau statique, mais ce n'est pas très élégant.

Alors si quelqu'un peut m'expliquer, ça me rendrait bien service.

Merci d'avance,
Eric
 

zeb

Modérateur
Salut,

L'instruction new alloue de l'espace sur le tas (heap).
Peut-être gères-tu mal la winmm.lib et cela remplit-il le tas.

La solution est dans doute à chercher du côté de ton utilisation de ta lib.
 

Rocky75

Expert
Je regarde de ce côté là.
Ma fonction qui exploite la lib winmm ne fait qu'un seul new, pour 392 octets, et qui marche bien. Elle fait aussi appel à des fonction de l'API multimédia de Windows, comme mixerOpen, mixerGetNumDevs, ...
Ce qui est marrant, c'est que quand je remplace le new de cette fonction en tableau statique, les new qui suivent se mettent à marcher !!
C'est à croire qu'un new de 392 octets sature le tas. Etonnant quand même...

Je continue à chercher.

[EDIT] Je me rends compte que le tas (heap) est dimensionné par défaut à 1 MO. C'est largement plus que l'espace que je consomme avec mes 'new', alors je ne comprends vraiment pas pourquoi ça plante...
 

batchy

Grand Maître
fait voir ton code ? (en respectant le règlement)

D'après la norme, quand new ne peut pas allouer de la mémoire, alors il lance une exception bad_alloc, et il doit pas retourner NULL.

quel compilateur utilise tu ?
 

Rocky75

Expert
J'utilise Visual C++ 2003. Je sais, c'est vieux, mais c'est tout ce que j'ai...
Difficile pour moi de montrer le code incriminé car il est dispersé mais je vais essayer quand même.
Voici:

1) Dans la phase d'initialisation, j'appelle la fonction InitAudio
Code:
status = InitAudio(hWnd);
Voici le contenu de la fonction en question:
Code:
typedef struct
{
	HMIXER hMixer;
	MIXERCAPS mixerCaps;
	MIXERLINE mixerLine;
	MIXERLINECONTROLS mixerLineControl;
	MIXERCONTROL mixerControl;
} AUDIO_MIXER;

static UINT nbDevices = 0;
static AUDIO_MIXER* mixer = 0;

BOOL InitAudio(HWND hWnd)
{
	UINT nbDev = mixerGetNumDevs();
	mixer = new AUDIO_MIXER[nbDevices];
	MMRESULT result;
	UINT n = 0;

	for (UINT i=0; i < nbDev; i++)
	{
		result = mixerOpen(&mixer[n].hMixer, i, (DWORD_PTR)hWnd, 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW);
		if (result != MMSYSERR_NOERROR)
			continue;

		if (result == MMSYSERR_NOERROR)
		{
			ZeroMemory(&mixer[n].mixerCaps, sizeof(MIXERCAPS));
			result = mixerGetDevCaps((UINT_PTR)mixer[n].hMixer, &mixer[n].mixerCaps, sizeof(MIXERCAPS));
			if (result != MMSYSERR_NOERROR)
				return FALSE;
		}
		else
			return FALSE;

		mixer[n].mixerLine.cbStruct = sizeof(MIXERLINE);
		mixer[n].mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
		result = mixerGetLineInfo((HMIXEROBJ)mixer[n].hMixer, &mixer[n].mixerLine, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);
		if (result != MMSYSERR_NOERROR)
			continue;

		mixer[n].mixerLineControl.cbStruct = sizeof(MIXERLINECONTROLS);
		mixer[n].mixerLineControl.dwLineID = mixer[n].mixerLine.dwLineID;
		mixer[n].mixerLineControl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
		mixer[n].mixerLineControl.cControls = 1;
		mixer[n].mixerLineControl.cbmxctrl = sizeof(MIXERCONTROL);
		mixer[n].mixerLineControl.pamxctrl = &mixer[n].mixerControl;
		result = mixerGetLineControls((HMIXEROBJ)mixer[n].hMixer, &mixer[n].mixerLineControl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
		if (result != MMSYSERR_NOERROR)
			return FALSE;
		n++;
	}
	nbDevices = n;
	return TRUE;
}
2) Après le retour de cette fonction avec succès, je fais plus loin dans le code le new qui plante:
Code:
static DWORD*		sliderValue = 0;
static POINT*	sliderPos = 0;
...
sliderValue = new int[nbItems];
sliderPos = new POINT[nbItems];
for (UINT i=0; i < nbItems; i++)
	sliderValue[i] = 0;
Sachant que nbItems vaut 3 et que sliderValue vaut 0 après le new, donc ça plante quand j'essaie d'initialiser les valeurs.

Il faut savoir que quand j'utilise le namespace std (dans l'espoir d'obtenir une exception), tout plante avant le catch.
Je m'explique:
Code:
#include <new>
using namespace std;
int* value;
...
int nb = 3;
try
{
    value = new int[nb];
}
catch (bad_alloc a)
{
    printf("%s\n", a.what());
}
Le printf n'est jamais executé, ça plante au niveau du new sans autre forme de procès.

Voilà... en espérant que ce n'est pas trop pénible à lire.

Eric
 

Rocky75

Expert
Meilleure réponse
En relisant le code copié ici, j'ai moi même trouvé l'erreur !!
Dans la fonction InitAudio, ligne 16, je fais un new avec nbDevices qui vaut 0, et ça fout la m...
Il faut plutôt écrire:
Code:
mixer = new AUDIO_MIXER[nbDev];
Je l'ai fait, et maintenant tout marche bien !!
Désolé d'avoir dérangé pour si peu, il me fallait un oeil extérieur :)

Eric
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 126
Messages
6 717 810
Membres
1 586 365
Dernier membre
matiOs1
Partager cette page
Haut