Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C: Varattujen resurssien automaattinen vapauttaminen MinGW/GCC

Okkaaj [18.10.2014 15:11:31]

#

Tämä vinkki käsittelee miten, milloin ja miksi käyttää GCC/MinGW:n cleanup laajennusta.

Ajoittain näkee C koodissa bugeja tai muistivuotoja koska käytettyjä resursseja ei ole vapautettu. Suositeltavaa on tarkastaa funktioiden palautusarvot ja mahdolliset virheet sekä vapauttaa varatut resurssit.

Tämä esimerkki käyttää WinAPI funktioita eikä sovellu käytettäväksi kuin Windowsissa, mutta sama periaate toimii kaikilla alustoilla jota GCC tukee.
Kuvittele, että sinun tulisi kirjoittaa C ohjelma joka lukee tiedoston muistiin ja palauttaa true jos luku onnistui.

Tässä on esimerkki miten moni sen tekisi:

BOOL esimerkki_1(LPCWSTR tiedostonimi)
{
	BOOL palautusarvo = TRUE;
	DWORD tarkistus = 0, tiedosto_koko = 0;

	PBYTE tiedosto_data = NULL;

	HANDLE hKahva = CreateFileW(tiedostonimi, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hKahva == INVALID_HANDLE_VALUE)
	{
		palautusarvo = FALSE;
		goto _virhe;
	}

	if ((tiedosto_koko = GetFileSize(hKahva, NULL)) == INVALID_FILE_SIZE)
	{
		palautusarvo = FALSE;
		goto _virhe;
	}

	if ((tiedosto_koko = malloc(tiedosto_koko)) == NULL)
	{
		palautusarvo = FALSE;
		goto _virhe;
	}

	if (!ReadFile(hKahva, tiedosto_koko, tiedosto_koko, &tarkistus, NULL) || tarkistus != tiedosto_koko)
	{
		palautusarvo = FALSE;
		goto _virhe;
	}

	palautusarvo = CloseHandle(hKahva);

_virhe: //Putsataan kaikki samassa paikassa
	if (hKahva != INVALID_HANDLE_VALUE) { CloseHandle(hKahva); }
	if (*tiedosto_data != NULL) { free(*tiedosto_data); }
	return palautusarvo;
}

Eli tarkistellaan virheet, ja putsataan kaikki käytetyt resurssit yhdessä paikassa ja palautetaan palautusarvo.

Seuraava esimerkki näyttää miten vapauttaa/sulkea käytetyt resurssit automaattisesti, käyttäen cleanup -laajennusta:

typedef HANDLE omaKahva  __attribute__((cleanup(sulje_kahva)));
typedef LPVOID omaData  __attribute__((cleanup(vapauta_resurssi)));


void sulje_kahva(HANDLE* kahva)
{
	if (kahva != NULL)
	{
		puts("Suljetaan kahva!");
		if (*kahva != NULL && *kahva != INVALID_HANDLE_VALUE)
		{
			CloseHandle(*kahva);
			*kahva = NULL;
		}
	}
}


void vapauta_resurssi(LPVOID* resurssi)
{
	if (resurssi != NULL)
	{
		{
			puts("Vapautetaan resurssi!");
			if (*resurssi != NULL)
			{
				free(*resurssi);
				*resurssi = NULL;
			}
		}
	}
}

BOOL esimerkki_2(LPCWSTR tiedostonimi)
{
	DWORD tarkistus = 0, tiedosto_koko = 0;

	omaData tiedosto_data = NULL;

	omaKahva hKahva = CreateFileW(tiedostonimi, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hKahva == INVALID_HANDLE_VALUE)
		return FALSE;

	if ((tiedosto_koko = GetFileSize(hKahva, NULL)) == INVALID_FILE_SIZE)
		return FALSE;

	if ((tiedosto_koko = malloc(tiedosto_koko)) == NULL)
		return FALSE;

	if (!ReadFile(hKahva, tiedosto_koko, tiedosto_koko, &tarkistus, NULL) || tarkistus != tiedosto_koko)
		return FALSE;

	return CloseHandle(hKahva);
}

...jolloin käytetyt resurssit vapautuu automaattisesti!


Ainakin GCC, MinGW ja Clang tukee cleanup laajennusta.
Ikävä kyllä Microsoftin kääntäjä ei tue sitä.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta