Koderskie Tippek és Trix

Szabályzat kódolási C ++ valódi szakemberek továbbra is vizsgálja a bonyolult memória kezelése C ++. A következő pár oldalt szentelnek a mélyreható vizsgálat az üzemeltetők új és törölni. Ilyen, akkor tudni fogja, hogy mire van szükség a C ++ szabvány egyéni megvalósítások ezek az üzemeltetők.







Az előző cikkben kellett kitalálni, hogy mit kell tennie, hogy cserélje ki a szereplők új és törölje a változatok, és ha lehet csinálni nélküle. mi is egy kicsit érintette, és megvitatták funktsiiobrabotchika új beállítási hiba vissza mutatót.

Rajta, fogunk beszélni egy kicsit alacsonyabb. Ezen kívül új samopisny vissza kell a helyes értéket, és a helyes eljárás iránti kérelmek elosztása byte nulla. Továbbá, ha a végrehajtási saját memória funkciókat, meg kell vigyázni, hogy ne elrejteni a „normál” formában. És most mindez részletesebben.

Megállapodás írásban az új üzemeltető első dolog új felhasználó visszatérhet a helyes értéket. Abban az esetben, egy sikeres elosztása, az üzemben tartó köteles visszatérni egy mutatót hozzá. Ha valami nem sikerült, meg kell dobni egy kivételt típusú bad_alloc.

De nem olyan könnyű, mint amilyennek látszik. Mielőtt az új kivétel a ciklusban ne okozzon a függvényt, amely megkísérli megoldani a problémás helyzetet. Mit kell ezt a funkciót, akkor részletesen megvizsgálták egy korábbi cikkben. Most csak emlékeztetni, hogy engedje a memória tartalék előre elkészített esetén hiány, önmagában egy kivételt, vagy akár megszüntetni a programot. Nagyon fontos, hogy kezelőfüggvény rendesen teljesül, mivel a hívás ciklus kerül végrehajtásra, amíg nem ütközik helyzet megoldódik. Egy másik fontos pont, amit meg kell vizsgálni - a kérelmek feldolgozásának elosztását nulla bájt memóriát. Bármilyen furcsán hangzik, de a C ++ szabvány megköveteli, ebben az esetben a helyes működését a kezelő. Ez a viselkedés egyszerűsíti végrehajtását néhány dolog más területein nyelvet. Mindezeket figyelembe véve, akkor próbálja terjeszteni az ál-egyéni, új:

A pszeudo-kód egy egyéni végrehajtása az új üzemeltető

void * operátor új (std :: size_t méret)
dobja (std :: bad_alloc)
using namespace std;
// a megbízást a 0 bájt
// kivéve, hogy meg kell kiosztani 1 byte
ha (méret == 0)
size = 1;
while (true)
// megpróbálunk kiosztani mérete byte;
if (kiosztani)
vissza (memória pointer);
// memóriát lefoglalni sikertelen
// ellenőrizzük, hogy a függvény neve
new_handler globalHandler = set_new_handler (0);
set_new_handler (globalHandler);
if (globalHandler)
(* GlobalHandler) ();
más
dobja STD :: bad_alloc ();
>
>

különösen érzékeny lehet, hogy megzavarja a elosztását egy bájtot, ha kérünk egy nulla. Igen, ez durva, de működik. A tény az, hogy vissza kell térnünk a megfelelő mutató, akkor is, ha arra kérik, hogy 0 bájt, ezért meg kell kitalálni. És annál könnyebb a találmány, így biztonságosabb.

Ismétlem, hogy az új üzemeltető problémák esetén memórialefoglalási végtelen ciklusba okozza a függvényt. Nagyon fontos, hogy a kódex ezt a funkciót helyesen oldotta meg a problémát, és hozzáférhetővé tett több memóriát keverjük kivétel típusát, amely származó bad_alloc, meg más kezelő, hogy az aktuális felvezető vagy nem tér vissza egyáltalán. Ellenkező esetben a program, ami miatt az új verzió, fog lógni.

Azt is meg kellene vizsgálni az esetet, amikor egy új funktsieychlenom minden osztályban. Általában egyéni változatát az ott dolgozó memória van írva, hogy jobban optimalizált memória kiosztás. Például, az új Base Class kihegyezett kiválasztással memória sizeof (Base) - nem több, nem kevesebb.

De mi történik, ha osztályt hozunk létre, amely örökli a Base? A származtatott osztály is használt változata szereplő új, meghatározott Base. De a méret a származtatott osztály (úgynevezett származtatott), valószínűleg különbözik a méret a bázis: sizeof (származtatott) = sizeof (Base) !. Emiatt az összes előnyeit önmegvalósítás új is semmivé. Mi, az úton, sok ember elfelejti majd tapasztalható embertelen szenvedés.

A probléma az öröklési az új üzemeltető

osztály Base nyilvános:
static void * operátor új (std :: size_t méret)
dobja (std :: bad_alloc);
.
>;
// az alosztály nyilvánították az új üzemeltető
osztály nyert: nyilvános adatbázisa
;
// úgynevezett Base :: operátor új






A származtatott * p = új származtatott;

Elegendő ahhoz, hogy megoldja a problémát könnyen, de ezt meg kell tenni előre. Elég az alap osztály, a szervezetben az üzemeltető új, hogy végezzen vizsgálatot a kiosztott memória méretét. Ha a bájtok számát kért nem egyezik meg a bájtok számát az alap osztály objektum, a munka memória kiosztás a legjobb, hogy adja át a standard végrehajtása az új. Ezen kívül, mivel azonnal megoldja a problémát feldolgozására irányuló kérelmet elosztása nulla bájt memóriát - ez már akkor részt vesz a teljes munkaidőben szereplő verzió.

A probléma megoldása az öröklési az új üzemeltető

void * operátor új (std :: size_t méret)
dobja (std :: bad_alloc)
// ha a méret nem megfelelő, hívja az új szabvány
if (méret! = sizeof (bázis))
visszatéréshez. operátor új (méret);
// egyébként kezelni a kérést
.
>

Azt is meghatározza az új tömbök az osztály szintjén (operátor új []). Ez az állítás nem kell tennie semmit, de kiosztani formázatlan memória blokk. Nem végezhet műveleteket a tárgyak még nem hozott létre. És különben is, nem tudjuk, hogy mekkorák ezek a tárgyak, mert örökösei az osztály, amely meghatározza az új []. Azaz, az objektumok száma egy sor adott esetben egyenlő (a bájtok számát kért) / sizeof (bázis). Továbbá, a dinamikus tömböket is lehet több memóriát igényel, mint a tárgyak maguk kerül, hogy biztosítsák az.

A pszeudo-kód egy egyéni végrehajtása a törlési üzemben

void * operátor törölni (void * rawMemory) throw ()
// ha null pointer, hogy nem tesz semmit
ha (rawMemory == 0) visszatérési;
// szabad a memória által mutatott
rawMemory;
>

Ha a törlés operátor egy tag függvény az osztály, mint ahogy az az új, ügyelni kell arra, hogy ellenőrizze a törölt memória méretét. Ha a felhasználó végrehajtására vonatkozó új Base Class kiosztott sizeof (Base) bájt memóriát, majd törölje samopisny kell engedniük az azonos számú bájt. Ellenkező esetben, ha az eltávolítható memória mérete nem egyezik a méret az osztály, amely meghatározza az üzemben közvetíteni a munka szokásos törölni.

Pszeudókód tag függvény törli

osztály Base nyilvános:
static void * operátor új (std :: size_t méret)
dobja (std :: bad_alloc);
static void * operátor törlése
(Érvénytelen rawMemory, std :: size_t méret) throw ();
.
>;
void * Base :: operator delete (void * rawMemory,
std :: size_t méret) throw ()
// ha null pointer, hogy nem tesz semmit
ha (rawMemory == 0) visszatérési;
if (méret! = sizeof (bázis)). kezelő törli (rawMemory);
return;
>
// szabad a memória által mutatott
rawMemory;
>

Az üzemeltetők az új és törölni elhelyezéssel

A funkció az üzemeltető új, hogy további paramétereket, az úgynevezett „új üzemeltető az elhelyezést.” Általában egy változó típusú void * mint egy további paramétert. Így a meghatározása elhelyezésére az új valahogy így néz ki:

void * operátor új (std :: size_t, void * pMemory)

Tágabb értelemben új elhelyezést vehet tetszőleges számú további paramétereket minden formáját. A törlés üzemeltető az úgynevezett „feltöltött” ugyanazon elv - azt is figyelembe venni mellett az alapvető és haladó beállítások.

Most nézzük meg az esetet, amikor dinamikusan létrehoz egy objektumot minden osztályban. A kód egy ilyen műveletet kell túl ismerős:

widgetet * pw = new Widget

Létrehozása egy objektum két szakaszban történik. Az első memóriát követelmények szabvány szereplő új, és egy második osztály konstruktora nevezzük Widget, ami inicializálja az objektumot. A helyzet állhat elő, amikor a memória az első lépésben kerül kiválasztásra és a kivitelező kivételt dob, és a mutató * pw marad inicializált. Achtung! Így hát ez egy potenciális memóriavesztés. Ennek elkerülése érdekében az oka kell, hogy időben a rendszer teljesítményét C ++. Akkor köteles felhívni a törlés üzemeltető memóriát az első lépésben létrehozásának egy tárgy. De van egy kis részlet, hogy lehet tönkretenni. C ++ ok törlésére, amelyek aláírása megegyezik az aláírás új, használt memória kiosztás. Amikor a szabványos formák új és törölhet, nincs gond, de ha írunk egy új zártkörű és felejtsd nakodil megfelelő formában törölni, akkor szinte száz százalékos a valószínűsége, hogy memóriavesztés, amikor kivételt dobott az osztályban kivitelező.

Az ilyen kód okozhat memóriavesztés

osztály Widget nyilvános:
.
static void * operátor új (std :: size_t méret,
std :: ostream logStream) dobás (std :: bad_alloc);
static void * operátor törölni (void * pMemory,
std :: size_t méret) throw ();
.
>;
Widget * pw = new (std :: cerr) Widget;

A megoldás erre a problémára az, hogy írjon egy törlési nyilatkozat aláírásával megfelelő aláírását az újat elhelyezést. Ha szükséges, szakítsa meg a kiosztást az üzemeltető törli lesz az úgynevezett C ++ runtime rendszer. A kód, ez nézhet:

Most nem kell szivárgás

osztály Widget nyilvános:
.
static void * operátor új (std :: size_t méret,
std :: ostream logStream)
dobja (std :: bad_alloc);
static void * operátor törölni (void * pMemory,
std :: size_t méret)
dobja ();
static void * operátor törölni (void * pMemory,
std :: ostream logStream)
dobja ();
.
>;
Widget * pw = new (std :: cerr) Widget;

Nem szabad elfelejteni, hogy a felépített objektum lehet eltávolítani a szabványos formában törlés. Teljesen elkerülni az összes lehetséges hibát memórialefoglalási, akkor hagyja ezt az opciót, és felszabadítása funkciókat.

Egy másik fontos pont kapcsolódik az eltitkolása funkció nevét. Ha úgy ítéljük meg, bármilyen formában, új, minden más szokásos formája a szolgáltató lesz elérhető.

elrejtése nevek

osztály Base nyilvános:
static void * operátor új (std :: size_t méret,
std :: ostream logStream)
dobja (std :: bad_alloc);
...
>;
// Hiba! A szokásos forma új rejtett
Base * pb = new Base;
// Ez így van, hívjon fel az új Base
Base * pb = new (std :: cerr) Base;

következtetés

Ezen a ponton már befejeződött foglalkozni sajátosságaival memória kezelése C ++ és kapott egy része hasznos tudást, hogy hasznos lesz, hogy minden magára valamit is adó jeladó. Míg újra találkozunk a levegőben!

Itt található az ezt a cikket egy ismerősének:

  • 42 perce

VPN-szolgáltató PureVPN elmagyarázta, hogyan segített az FBI, hogy letartóztassák egyik tagját

Google bírálta a Microsoft Update rendszer. A Microsoft válasza beszélt RCE-bug Chrome