Cztery rodzaje operatora new

2008-05-20 21:04

Do alokowania pamięci (albo raczej: tworzenia obiektów na stercie) służy w C++ operator o wiele mówiącej nazwie new. Chociaż jest on powszechnie znany i nieustannie używany przez każdego programistę C++, pewni nie wszyscy wiedzą, że występuje on nie w jednej, ale aż w czterech odmianach, z których każda różni się sposobem wywołania!
Oto krótki przegląd:

  • “Zwykły” operator new (co obejmuje też formę tablicową new[]) jest oczywiście najbardziej znany i najczęściej stosowany. Warto pamiętać, że zazwyczaj robi on dwie rzeczy: oprócz alokacji pamięci wywołuje też konstruktor dla tworzonego obiektu (lub obiektów w tablicy), któremu możemy też podać parametry.
  • Przeciążony operator new zmienia natomiast swoje zachowanie tylko w zakresie tej pierwszej czynności, czyli samej alokacji. Ciekawostką jest to, że możemy wyposażyć go (tj. sam operator new) w dodatkowe parametry – czyli przeciążyć go w pełnym znaczeniu tego słowa! Typowym przykładem, jaki się tutaj zwykle przytacza, jest następująca funkcja:
    1. void* operator new (size_t bytes, char fill)
    2. {
    3.     // alokacja z wypełnieniem podanym wzorcem
    4.     char* p = ::new char[bytes];
    5.     for (size_t i = 0; i < bytes; ++i) p&#91;i] = fill;
    6.     return p;
    7. }&#91;/cpp]
    8. która tworzy przeciążoną wersję operatora <code>new</code>, wypełniającą świeżo zaalokowaną pamięć podanym wzorcem:
    9. [cpp]char* ptr = new('X') char[10];  // alokuje tablicę charów wypełnioną X-ami

    Naturalnie możliwe są bardziej przydatne zastosowania. Jeśli mamy na przykład kilka rozłącznych ze sobą stert, to możemy tak napisać operator new, by poprzez dodatkowy argument pozwalał decydować o tym, którą z nich chcemy w danym przypadku wybrać.

  • new nierzucający wyjątków. Domyślnie alokacja za pomocą new rzuca wyjątek std::badalloc, jeżeli operacja się nie powiodła (zwykle z powodu braku pamięci). To zachowanie – wymagające do poprawnej obsługi bloku try-catch może nam się nie podobać, ale na szczęście można je zmienić. Wystarczy użyć wersji new z dodatkowym parametrem std::nothrow:
    1. int* pEnormousArray = new(std::nothrow) int[0xffffffff]; // "tylko" 4GB :)

    Wymaga to jeszcze dołączenia standardowego pliku nagłówkowego o wielce trafnej nazwie new.

  • Ostatni rodzaj zwie się placement new, co nie ma żadnego specjalnie dobrego tłumaczenia na język polski. Użycie tego operatora wymaga podania wskaźnika na już zaalokowany kawałek pamięci. Działanie operatora new ogranicza się wtedy do skonstruowania obiektu w tym właśnie miejscu, na które pokazuje przekazany wskaźnik. Tak więc w tym przypadku new tak naprawdę niczego nie alokuje; jest to po prostu najzupełniej legalny sposób na wywołanie konstruktora bez robienia czegokolwiek innego. Jakkolwiek może to się wydawać przydatne, zdecydowanie odradzam korzystania z tego mechanizmu w sposób nieprzemyślany, bo można przy tym popełnić “ciekawe” błędy.

Mamy więc aż cztery różne warianty new, ale raczej nie powinno to rodzić dylematów w rodzaju “Który z nich wybrać?”. W praktyce i tak nieczęsto zachodzi potrzeba skorzystania z któregokolwiek poza pierwszym. Co nie znaczy rzecz jasna, że nie warto znać pozostałych – podobnie jak całej masy innych kruczków języka C++ :]

Tags: , ,
Author: Xion, posted under Programming »


4 comments for post “Cztery rodzaje operatora new”.
  1. ed:
    May 20th, 2008 o 21:49

    A propo ostatniego “new” i tekstu “obiekty są pamiętliwe” to ten problem dotyczy wszystkich obiektów.

    Foo* o = new Foo();
    o->Time = 10.0f;
    delete o;
    Foo* o2 = new Foo();

    Pytanie: jaką wartość będzie mieć zmienna Time w drugim obiekcie ? (dodam że konstruktor jej nie inicjalizuje :)

    A co do tego że nie działał Ci placement new, to głównie dlatego że twoja klasa CTexture dziedziczyła po IDxResource co już samo to było słabym pomysłem :)

  2. Xion:
    May 20th, 2008 o 22:46

    Owszem było :)

    A co do pytania… Jeśli faktycznie 10.0f, to wyłącznie przypadek i zachowanie zależne od implementacji sposobu zarządzania stertą. Naturalnie świadczy ono jak najlepiej o tym sposobie (ponowne wykorzystanie zwolnionych bloków). Nie zmienia to jednak faktu, że jeśli nie inicjujemy tego pola w konstruktorze, to powinniśmy je traktować jako zawierające wartość nieokreśloną.

  3. macabre13:
    May 21st, 2008 o 8:29

    placement new – Tlumacza na new ‘umieszczajcacy’

  4. RedHot:
    May 21st, 2008 o 12:43

    @up

    Sądzę, że większość osób wie co oznacza placement ^^’. Sęk w tym by ująć to jakoś zgrabnie.

Comments are disabled.
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.