new operator (C++)

Próbuje przydzielić i zainicjować obiekt lub tablicę obiektów określonego lub zastępczego typu i zwraca odpowiednio wpisany wskaźnik niezerowy do obiektu (lub do początkowego obiektu tablicy).

Składnia

new-expression:
::opt optnewnew-placementnew-type-idnew-initializer
::opt optnewnew-placement(type-id)new-initializer

new-placement:
( expression-list )

new-type-id:
type-specifier-seqnew-declaratorZdecydować

new-declarator:
ptr-operatornew-declaratorZdecydować
noptr-new-declarator

noptr-new-declarator:
[expression]attribute-specifier-seqZdecydować
noptr-new-declarator[constant-expression]attribute-specifier-seqZdecydować

new-initializer:
(expression-listZdecydować)
braced-init-list

Uwagi

Jeśli błąd nie powiedzie się, new zwraca zero lub zgłasza wyjątek. Aby uzyskać więcej informacji, zobacz Operatorynew i delete . To domyślne zachowanie można zmienić, pisząc niestandardową procedurę obsługi wyjątków i wywołując _set_new_handler funkcję biblioteki czasu wykonywania z nazwą funkcji jako jej argumentem.

Aby uzyskać informacje na temat tworzenia obiektu na zarządzanym stercie w języku C++/CLI i C++/CX, zobacz gcnew.

Uwaga

Rozszerzenia składników języka Microsoft C++ (C++/CX) zapewniają obsługę słowa kluczowego służącego new do dodawania wpisów gniazda tabeli wirtualnej. Aby uzyskać więcej informacji, zobacz new (nowe miejsce w tabeli wirtualnej)

Gdy new jest używana do przydzielania pamięci dla obiektu klasy C++, konstruktor obiektu jest wywoływany po przydzieleniu pamięci.

Użyj operatora , delete aby cofnąć przydział pamięci przydzielonej new przez operatora. delete[] Użyj operatora , aby usunąć tablicę przydzieloną new przez operatora.

Poniższy przykład przydziela, a następnie zwalnia dwuwymiarową tablicę znaków o rozmiarze dim 10. Podczas przydzielania tablicy wielowymiarowej wszystkie wymiary z wyjątkiem pierwszego muszą być wyrażeniami stałymi, które oceniają wartości dodatnie. Najbardziej lewy wymiar tablicy może być dowolnym wyrażeniem, które daje wartość dodatnią. Podczas przydzielania tablicy przy użyciu new operatora pierwszy wymiar może być zerowy; new operator zwraca unikatowy wskaźnik.

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

Element type-id nie może zawierać constdeklaracji klasy , volatilelub deklaracji wyliczenia. Następujące wyrażenie jest źle sformułowane:

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

Operator new nie przydziela typów odwołań, ponieważ nie są obiektami.

Nie new można użyć operatora do przydzielenia funkcji, ale może służyć do przydzielania wskaźników do funkcji. Poniższy przykład przydziela, a następnie zwalnia tablicę siedmiu wskaźników do funkcji, które zwracają liczby całkowite.

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

Jeśli używasz operatora new bez dodatkowych argumentów i kompilujesz z opcją /GX, /EHalub /EHs , kompilator generuje kod do wywołania operatora delete , jeśli konstruktor zgłosi wyjątek.

Na poniższej liście opisano elementy gramatyczne elementu new:

new-placement
Zapewnia sposób przekazywania dodatkowych argumentów, jeśli przeciążysz newelement .

type-id
Określa typ, który ma zostać przydzielony; może być wbudowanym lub zdefiniowanym przez użytkownika typem. Jeśli specyfikacja typu jest skomplikowana, można ją otaczać nawiasami, aby wymusić kolejność powiązania. Typ może być symbolem zastępczym (auto), którego typ jest określany przez kompilator.

new-initializer
Zawiera wartość zainicjowanego obiektu. Nie można określić inicjatorów dla tablic. Operator new utworzy tablice obiektów tylko wtedy, gdy klasa ma konstruktor domyślny.

noptr-new-declarator
Określa granice tablicy. Podczas przydzielania tablicy wielowymiarowej wszystkie wymiary, z wyjątkiem pierwszego muszą być wyrażeniami stałymi, które oceniają wartości dodatnie, konwertowane na std::size_twartość . Najbardziej lewy wymiar tablicy może być dowolnym wyrażeniem, które daje wartość dodatnią. Wartość attribute-specifier-seq ma zastosowanie do skojarzonego typu tablicy.

Przykład: przydzielanie i zwalnianie tablicy znaków

Poniższy przykład kodu przydziela tablicę znaków i obiekt klasy CName , a następnie zwalnia je.

// 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;
}

Przykład: new operator

Jeśli używasz formularza new umieszczania operatora (formularza z większymi argumentami niż rozmiar), kompilator nie obsługuje formularza delete umieszczania operatora, jeśli konstruktor zgłasza wyjątek. Przykład:

// 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;
}

Inicjowanie obiektów przydzielonych za pomocą polecenia new

Opcjonalne new-initializer pole jest uwzględniane w gramatyce operatora new . To pole umożliwia inicjowanie nowych obiektów za pomocą konstruktorów zdefiniowanych przez użytkownika. Aby uzyskać więcej informacji na temat sposobu inicjowania, zobacz Initializers (Inicjatory). W poniższym przykładzie pokazano, jak używać wyrażenia inicjalizacji z operatorem 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 };
    // ...
}

W tym przykładzie obiekt CheckingAcct jest przydzielany przy użyciu new operatora, ale nie określono domyślnej inicjowania. Dlatego jest wywoływany domyślny konstruktor klasy Acct(), . Następnie obiekt SavingsAcct jest przydzielany w taki sam sposób, z tą różnicą, że jawnie zainicjowano go do wersji 34.98. Ponieważ 34.98 jest typu double, konstruktor, który przyjmuje argument tego typu, jest wywoływany w celu obsługi inicjowania. Na koniec typ HowMuch nieklasowy jest inicjowany do wersji 43.0.

Jeśli obiekt jest typu klasy i klasa ma konstruktory (jak w poprzednim przykładzie), obiekt może zostać zainicjowany przez new operatora tylko wtedy, gdy zostanie spełniony jeden z tych warunków:

  • Argumenty podane w inicjatorze są zgodne z argumentami konstruktora.

  • Klasa ma domyślny konstruktor (konstruktor, który można wywołać bez argumentów).

Jawne inicjowanie poszczególnych elementów nie można wykonać podczas przydzielania tablic przy użyciu new operatora; wywoływany jest tylko konstruktor domyślny, jeśli istnieje. Aby uzyskać więcej informacji, zobacz Argumenty domyślne.

Jeśli alokacja pamięci zakończy się niepowodzeniem (operator new zwraca wartość 0), nie zostanie wykonana żadna inicjalizacja. To zachowanie chroni przed próbami zainicjowania danych, które nie istnieją.

Podobnie jak w przypadku wywołań funkcji, kolejność oceniania wyrażeń zainicjowanych nie jest zdefiniowana. Ponadto nie należy polegać na tym, że wyrażenia są obliczane całkowicie przed rozpoczęciem alokacji pamięci. Jeśli alokacja pamięci zakończy się niepowodzeniem, a new operator zwróci zero, niektóre wyrażenia w inicjatorze mogą nie być obliczane całkowicie.

Okres istnienia obiektów przydzielonych za pomocą polecenia new

Obiekty przydzielone operatorowi new nie są niszczone, gdy zakres, w którym są zdefiniowane, jest zamykany. new Ponieważ operator zwraca wskaźnik do przydzielanych obiektów, program musi zdefiniować wskaźnik z odpowiednim zakresem, aby uzyskać dostęp do tych obiektów i usunąć je. Przykład:

// 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.
}

Gdy wskaźnik AnotherArray wykracza poza zakres w tym przykładzie, nie można już usunąć obiektu.

Jak new to działa

Wyrażenie new-expression (zawierające new operator) wykonuje trzy czynności:

  • Lokalizuje i rezerwuje pamięć dla obiektu lub obiektów, które mają zostać przydzielone. Po zakończeniu tego etapu zostanie przydzielona prawidłowa ilość miejsca do magazynowania, ale nie jest jeszcze obiektem.

  • Inicjalizuje obiekt(y). Po zakończeniu inicjalizacji, wystarczająca ilość informacji jest obecna dla przydzielenia pamięci, która ma być obiektem.

  • Zwraca wskaźnik do obiektów typu wskaźnika pochodzącego z new-type-id lub type-id. Program używa tego wskaźnika do dostępu do nowo przydzielonego obiektu.

Operator new wywołuje funkcję operator new. W przypadku tablic dowolnego typu i obiektów, które nie classsą typami , structlub union , funkcja ::operator newglobalna , jest wywoływana w celu przydzielenia magazynu. Obiekty typu klasy mogą definiować własną operator new statyczną funkcję składową dla poszczególnych klas.

Gdy kompilator napotka new operator w celu przydzielenia obiektu typu T, wystawia wywołanie metody T::operator new( sizeof(T) ) lub, jeśli nie zdefiniowano operator new żadnego użytkownika, ::operator new( sizeof(T) ). W ten sposób new operator może przydzielić prawidłową ilość pamięci dla obiektu.

Uwaga

Argumentem do operator new jest typ std::size_t. Ten typ jest definiowany w pliku direct.h>, <malloc.h>, <memory.h>, <search.h>, <stddef.h>, <stdio.h>, <stdlib.h>, <string.h> i <time.h><.

Opcja w gramatyce umożliwia określenie new-placement (zobacz Gramatyka dla new operatora). Parametr new-placement może służyć tylko do implementacji zdefiniowanych operator newprzez użytkownika ; umożliwia przekazywanie dodatkowych informacji do operator newelementu . Wyrażenie z polem new-placement takim jak T *TObject = new ( 0x0040 ) T; jest tłumaczone na T *TObject = T::operator new( sizeof( T ), 0x0040 ); , jeśli klasa T ma składową operator new, w przeciwnym razie na T *TObject = ::operator new( sizeof( T ), 0x0040 );.

Pierwotnym zamiarem new-placement pola było umożliwienie przydzielania obiektów zależnych od sprzętu na adresach określonych przez użytkownika.

Uwaga

Mimo że w poprzednim przykładzie pokazano tylko jeden argument w new-placement polu, nie ma ograniczenia liczby dodatkowych argumentów, które można przekazać w operator new ten sposób.

Nawet jeśli operator new zdefiniowano dla typu Tklasy , można jawnie użyć operatora new globalnego, jak w tym przykładzie:

T *TObject = ::new TObject;

Operator rozpoznawania zakresu (::) wymusza użycie operatora globalnego new .

Zobacz też

Wyrażenia z operatorami jednoargumentowymi
Słowa kluczowe
newoperatory i delete