Sdílet prostřednictvím


new – operátor (C++)

Pokusí se přidělit a inicializovat objekt nebo pole objektů zadaného nebo zástupného typu a vrátí vhodný typ nenulového ukazatele na objekt (nebo na počáteční objekt pole).

Syntaxe

new-expression:
::optnew-placementoptnew-initializernew-type-idnew
::optopt)new-initializertype-id(newnew-placement

new-placement:
( expression-list )

new-type-id:
type-specifier-seqnew-declaratorRozhodnout

new-declarator:
ptr-operatornew-declaratorRozhodnout
noptr-new-declarator

noptr-new-declarator:
[expression]attribute-specifier-seqRozhodnout
noptr-new-declarator[constant-expression]attribute-specifier-seqRozhodnout

new-initializer:
(expression-listRozhodnout)
braced-init-list

Poznámky

Pokud se nezdaří, new vrátí nulu nebo vyvolá výjimku. Další informace naleznete v tématu Operátory a delete operátorynew. Toto výchozí chování můžete změnit tak, že jako argument napíšete vlastní rutinu zpracování výjimek a zavoláte _set_new_handler funkci knihovny runtime s názvem vaší funkce.

Informace o tom, jak vytvořit objekt ve spravované haldě v C++/CLI a C++/CX, najdete v tématu gcnew.

Poznámka

Rozšíření komponent Microsoft C++ (C++/CX) poskytuje podporu klíčového new slova pro přidání položek slotu vtable. Další informace najdete v tématu new (nový slot v tabulce vtable)

Pokud new se používá k přidělení paměti pro objekt třídy C++, je volána konstruktor objektu po přidělení paměti.

Pomocí operátoru delete uvolněte paměť přidělenou operátorem new . Pomocí operátoru delete[] odstraňte pole přidělené operátorem new .

Následující příklad přidělí a potom uvolní dvojrozměrnou matici znaků o velikosti dim 10. Při přidělování multidimenzionálního pole musí být všechny dimenze s výjimkou první konstantní výrazy, které se vyhodnotí jako kladné hodnoty. Maticová dimenze úplně vlevo může být libovolný výraz, který se vyhodnotí jako kladná hodnota. Při přidělování pole pomocí operátoru new může být první dimenze nula; new operátor vrátí jedinečný ukazatel.

char (*pchar)[10] = new char[dim][10];
delete [] pchar;

Nemůže type-id obsahovat const, , , volatiledeklarace tříd nebo výčtové deklarace. Následující výraz je neformulovaný:

volatile char *vch = new volatile char[20];

Operátor new nepřiděluje referenční typy, protože nejsou objekty.

Operátor new se nedá použít k přidělení funkce, ale dá se použít k přidělení ukazatelů na funkce. Následující příklad přidělí a potom uvolní pole sedmi ukazatelů na funkce, které vracejí celá čísla.

int (**p) () = new (int (*[7]) ());
delete p;

Pokud použijete operátor new bez dalších argumentů a zkompilujete s parametrem /GX, /EHanebo /EHs možnost, kompilátor vygeneruje kód pro volání operátor delete , pokud konstruktor vyvolá výjimku.

Následující seznam popisuje gramatické prvky new:

new-placement
Poskytuje způsob předávání nadbytečných argumentů při přetížení new.

type-id
Určuje typ, který má být přidělen; může to být předdefinovaný nebo uživatelem definovaný typ. Pokud je specifikace typu složitá, může být ohraničena závorky a vynutit pořadí vazby. Typ může být zástupný symbol (auto), jehož typ je určen kompilátorem.

new-initializer
Poskytuje hodnotu pro inicializovaný objekt. Inicializátory nelze zadat pro pole. Operátor new vytvoří pole objektů pouze v případě, že třída má výchozí konstruktor.

noptr-new-declarator
Určuje hranice pole. Při přidělování multidimenzionálního pole musí být všechny dimenze s výjimkou první konstantní výrazy, které se vyhodnocují jako kladné hodnoty konvertibilní na std::size_t. Maticová dimenze úplně vlevo může být libovolný výraz, který se vyhodnotí jako kladná hodnota. Platí attribute-specifier-seq pro přidružený typ pole.

Příklad: Přidělení a uvolnění pole znaků

Následující příklad kódu přidělí pole znaků a objekt třídy CName a pak je uvolní.

// expre_new_Operator.cpp
// compile with: /EHsc
#include <string.h>

class CName {
public:
   enum {
      sizeOfBuffer = 256
   };

   char m_szFirst[sizeOfBuffer];
   char m_szLast[sizeOfBuffer];

public:
   void SetName(char* pszFirst, char* pszLast) {
     strcpy_s(m_szFirst, sizeOfBuffer, pszFirst);
     strcpy_s(m_szLast, sizeOfBuffer, pszLast);
   }

};

int main() {
   // Allocate memory for the array
   char* pCharArray = new char[CName::sizeOfBuffer];
   strcpy_s(pCharArray, CName::sizeOfBuffer, "Array of characters");

   // Deallocate memory for the array
   delete [] pCharArray;
   pCharArray = NULL;

   // Allocate memory for the object
   CName* pName = new CName;
   pName->SetName("Firstname", "Lastname");

   // Deallocate memory for the object
   delete pName;
   pName = NULL;
}

Příklad: new operátor

Pokud použijete formu umístění operátoru new (formulář s více argumenty než velikost), kompilátor nepodporuje formulář delete umístění operátoru, pokud konstruktor vyvolá výjimku. Příklad:

// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
   A(int) { throw "Fail!"; }
};
void F(void) {
   try {
      // heap memory pointed to by pa1 will be deallocated
      // by calling ::operator delete(void*).
      A* pa1 = new A(10);
   } catch (...) {
   }
   try {
      // This will call ::operator new(size_t, char*, int).
      // When A::A(int) does a throw, we should call
      // ::operator delete(void*, char*, int) to deallocate
      // the memory pointed to by pa2.  Since
      // ::operator delete(void*, char*, int) has not been implemented,
      // memory will be leaked when the deallocation can't occur.

      A* pa2 = new(__FILE__, __LINE__) A(20);
   } catch (...) {
   }
}

int main() {
   A a;
}

Inicializace objektů přidělených pomocí new

new-initializer Volitelné pole je součástí gramatiky operátorunew. Toto pole umožňuje inicializaci nových objektů pomocí uživatelem definovaných konstruktorů. Další informace o tom, jak se inicializace provádí, najdete v tématu Inicializátory. Následující příklad ukazuje, jak použít inicializační výraz s operátorem new :

// expre_Initializing_Objects_Allocated_with_new.cpp
class Acct
{
public:
    // Define default constructor and a constructor that accepts
    //  an initial balance.
    Acct() { balance = 0.0; }
    Acct( double init_balance ) { balance = init_balance; }
private:
    double balance;
};

int main()
{
    Acct *CheckingAcct = new Acct;
    Acct *SavingsAcct = new Acct ( 34.98 );
    double *HowMuch = new double { 43.0 };
    // ...
}

V tomto příkladu je objekt CheckingAcct přidělen pomocí operátoru new , ale není zadána žádná výchozí inicializace. Proto je volána výchozí konstruktor pro třídu. Acct() Pak je objekt SavingsAcct přidělen stejným způsobem, s tím rozdílem, že je explicitně inicializován na 34,98. Protože 34.98 je typu double, konstruktor, který přebírá argument tohoto typu je volána pro zpracování inicializace. Nakonec se typ HowMuch , který není třída, inicializuje na 43.0.

Pokud je objekt typu třídy a tato třída má konstruktory (jako v předchozím příkladu), lze objekt inicializovat operátorem new pouze v případě, že je splněna jedna z těchto podmínek:

  • Argumenty zadané v inicializátoru odpovídají argumenty konstruktoru.

  • Třída má výchozí konstruktor (konstruktor, který lze volat bez argumentů).

Explicitní inicializace jednotlivých prvků nelze provést při přidělování polí pomocí operátoru new ; volá se pouze výchozí konstruktor, pokud je k dispozici. Další informace naleznete v tématu Výchozí argumenty.

Pokud přidělení paměti selže (operator new vrátí hodnotu 0), neprojde žádná inicializace. Toto chování chrání před pokusy o inicializaci dat, která neexistují.

Stejně jako u volání funkcí není definováno pořadí, ve kterém se inicializované výrazy vyhodnocují. Kromě toho byste se neměli spoléhat na to, že se tyto výrazy vyhodnocují úplně před přidělením paměti. Pokud přidělení paměti selže a operátor vrátí nulu new , některé výrazy v inicializátoru nemusí být vyhodnoceny úplně.

Doba života objektů přidělených pomocí new

Objekty přidělené operátorem new se při ukončení oboru, ve kterém jsou definovány, nezničí. Vzhledem k tomu, že new operátor vrátí ukazatel na objekty, které přiděluje, musí program definovat ukazatel s vhodným oborem pro přístup k těmto objektům a odstranit je. Příklad:

// expre_Lifetime_of_Objects_Allocated_with_new.cpp
// C2541 expected
int main()
{
    // Use new operator to allocate an array of 20 characters.
    char *AnArray = new char[20];

    for( int i = 0; i < 20; ++i )
    {
        // On the first iteration of the loop, allocate
        //  another array of 20 characters.
        if( i == 0 )
        {
            char *AnotherArray = new char[20];
        }
    }

    delete [] AnotherArray; // Error: pointer out of scope.
    delete [] AnArray;      // OK: pointer still in scope.
}

Jakmile ukazatel AnotherArray v příkladu překročí obor, nelze již objekt odstranit.

Jak new funguje

Výraz new-expression obsahující new operátor dělá tři věci:

  • Vyhledává a vyhrazuje úložiště pro objekt nebo objekty, které mají být přiděleny. Po dokončení této fáze se přidělí správné množství úložiště, ale zatím se nejedná o objekt.

  • Inicializuje objekt(y). Po dokončení inicializace je k dispozici dostatek informací pro přidělené úložiště, aby byl vytvořen objekt.

  • Vrátí ukazatel na objekty typu ukazatele odvozeného od new-type-id nebo type-id. Program používá tento ukazatel pro přístup k nově přidělenému objektu.

Operátor new vyvolá funkci operator new. Pro pole libovolného typu a pro objekty, které nejsou class, structnebo union typy, globální funkce, ::operator newje volána k přidělení úložiště. Objekty typu třídy mohou definovat vlastní operator new statickou členovou funkci na základě jednotlivých tříd.

Když kompilátor narazí na new operátor přidělení objektu typu T, vydá volání T::operator new( sizeof(T) ) nebo, pokud není definován žádný uživatelem definovaný operator new , ::operator new( sizeof(T) ). Je to způsob, jakým new může operátor přidělit správné množství paměti objektu.

Poznámka

operator new Argument typu std::size_t. Tento typ je definován v <direct.h>, <malloc.h>, <memory.h>, <search.h>, <stddef.h>, <stdio.h>, <stdlib.h>, <string.h> a <time.h>.

Možnost v gramatikě umožňuje specifikaci new-placement (viz Gramatika pro new operátor). Parametr new-placement lze použít pouze pro uživatelem definované implementace operator new; umožňuje předání dodatečných informací operator new. Výraz s polem new-placement , jako T *TObject = new ( 0x0040 ) T; je například přeložen do T *TObject = T::operator new( sizeof( T ), 0x0040 ); třídy T má člen operator new, jinak na T *TObject = ::operator new( sizeof( T ), 0x0040 );.

Původním záměrem new-placement pole bylo umožnit přidělení hardwarových objektů závislých na uživatelích.

Poznámka

I když předchozí příklad ukazuje pouze jeden argument v new-placement poli, neexistuje žádné omezení, kolik dalších argumentů lze tímto operator new způsobem předat.

I když operator new byl definován pro typ Ttřídy , můžete použít globální operátor new explicitně, jako v tomto příkladu:

T *TObject = ::new TObject;

Operátor rozlišení oboru (::) vynutí použití globálního new operátoru.

Viz také

Výrazy s unárními operátory
Klíčová slova
new a delete operátory