new оператор (C++)

Пытается выделить и инициализировать объект или массив объектов указанного или заполнителя и возвращает подходящий типизированный ненулевой указатель на объект (или начальный объект массива).

Синтаксис

new-expression:
::optnewnew-placementoptnew-type-idnew-initializeropt
::optnewnew-placementopt(type-id)new-initializeropt

new-placement:
( expression-list )

new-type-id:
type-specifier-seqnew-declaratorнеоб.

new-declarator:
ptr-operatornew-declaratorнеоб.
noptr-new-declarator

noptr-new-declarator:
[expression]attribute-specifier-seqнеоб.
noptr-new-declarator[constant-expression]attribute-specifier-seqнеоб.

new-initializer:
(expression-listнеоб.)
braced-init-list

Замечания

Если ошибка, new возвращается ноль или вызывает исключение. Дополнительные сведения см. в разделе "Операторы" и delete "newОператоры". Это поведение по умолчанию можно изменить, написав настраиваемую подпрограмму обработки исключений и вызвав _set_new_handler функцию библиотеки времени выполнения с именем функции в качестве аргумента.

Сведения о создании объекта в управляемой куче в C++/CLI и C++/CX см . в разделе gcnew.

Примечание.

Расширения компонентов Microsoft C++ (C++/CX) обеспечивают поддержку new ключевое слово добавления записей слотов vtable. Дополнительные сведения см. в разделе new (новый слот в vtable)

Если new используется для выделения памяти для объекта класса C++, конструктор объекта вызывается после выделения памяти.

delete Используйте оператор, чтобы освободить память, выделенную операторомnew. delete[] Используйте оператор для удаления массива, выделенного операторомnew.

В следующем примере выделяется и затем освобождается двумерный массив символов размером dim на 10. При выделении многомерного массива все измерения, кроме первого, должны быть константными выражениями, которые оцениваются положительными значениями. Самое левое измерение массива может быть любым выражением, которое оценивается положительным значением. При выделении массива new с помощью оператора первое измерение может быть равно нулю; new оператор возвращает уникальный указатель.

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

Не type-id удается содержать const, volatileобъявления классов или объявления перечисления. Следующее выражение является плохо сформированным:

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

Оператор new не выделяет ссылочные типы, так как они не объекты.

Оператор new не может использоваться для выделения функции, но его можно использовать для выделения указателей на функции. В следующем примере выделяется и затем освобождается массив из семи указателей на функции, которые возвращают целые числа.

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

Если оператор new используется без дополнительных аргументов и компилируется с /GXпараметром , /EHaили /EHs параметром, компилятор создает код для вызова оператора delete , если конструктор создает исключение.

В следующем списке описываются элементы грамматики new:

new-placement
Предоставляет способ передачи дополнительных аргументов при перегрузке new.

type-id
Указывает тип, который нужно выделить; это может быть встроенный или определяемый пользователем тип. Если спецификация типа является сложной, она может быть окружена круглыми скобками, чтобы принудительно реализовать порядок привязки. Тип может быть заполнителем (auto), тип которого определяется компилятором.

new-initializer
Предоставляет значение для инициализированного объекта. Инициализаторы не могут быть указаны для массивов. Оператор new создаст массивы объектов только в том случае, если класс имеет конструктор по умолчанию.

noptr-new-declarator
Задает границы массива. При выделении многомерного массива все измерения, кроме первого, должны быть константными выражениями, которые оцениваются в положительные значения, преобразуемые std::size_tв . Самое левое измерение массива может быть любым выражением, которое оценивается положительным значением. Применяется attribute-specifier-seq к связанному типу массива.

Пример. Выделение и освобождение массива символов

В следующем примере кода выделяется и освобождается массив символов и объект класса CName.

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

Пример: new оператор

Если используется форма размещения оператора (форма с большим количеством аргументов, чем размер), компилятор не поддерживает форму newdelete размещения оператора, если конструктор создает исключение. Например:

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

Инициализация объектов, выделенных с помощью new

Необязательное new-initializer поле включается в грамматику для new оператора. Это поле позволяет инициализировать новые объекты с помощью определяемых пользователем конструкторов. Дополнительные сведения о том, как выполняется инициализация, см. в разделе "Инициализаторы". В следующем примере показано, как использовать выражение инициализации с оператором 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 };
    // ...
}

В этом примере объект CheckingAcct выделяется с помощью new оператора, но инициализация по умолчанию не указана. Поэтому вызывается конструктор по умолчанию для класса Acct(). Затем объект SavingsAcct выделяется таким же образом, за исключением того, что он явно инициализирован до 34,98. Так как 34.98 имеет тип double, конструктор, принимаюющий аргумент этого типа, вызывается для обработки инициализации. Наконец, тип HowMuch , отличный от класса, инициализирован до 43.0.

Если объект имеет тип класса и этот класс имеет конструкторы (как и в предыдущем примере), объект можно инициализировать оператором new , только если выполняется одно из этих условий:

  • Аргументы, предоставленные в инициализаторе, соответствуют аргументам конструктора.

  • Класс имеет конструктор по умолчанию (конструктор, который можно вызвать без аргументов).

Явное инициализация для каждого элемента не может выполняться при выделении массивов с помощью new оператора; вызывается только конструктор по умолчанию, если он присутствует. Дополнительные сведения см. в разделе "Аргументы по умолчанию".

Если выделение памяти завершается сбоем (operator new возвращает значение 0), инициализация не выполняется. Это поведение защищает от попыток инициализации данных, которые не существуют.

Как и при вызовах функций, порядок вычисления инициализированных выражений не определен. Кроме того, вы не должны полагаться на эти выражения, которые оцениваются полностью перед выделением памяти. Если выделение памяти завершается ошибкой, а new оператор возвращает ноль, некоторые выражения в инициализаторе могут не оцениваться полностью.

Время существования объектов, выделенных с помощью new

Объекты, выделенные операторомnew, не уничтожаются при выходе область, в которой они определены. new Так как оператор возвращает указатель на выделенные объекты, программа должна определить указатель с подходящим область для доступа к этим объектам и удаления этих объектов. Например:

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

После того как указатель AnotherArray в этом примере вышел за пределы области видимости, объект невозможно удалить.

Как работает new

Выражение new-expression , new содержащее оператор, выполняет три действия:

  • Находит и резервирует хранилище для объекта или объектов, которым нужно выделить память. По завершении этого этапа выделяется правильный объем хранилища, но он еще не является объектом.

  • Инициализирует объекты. После завершения инициализации имеется достаточно информации, чтобы выделенная память являлась объектом.

  • Возвращает указатель на объекты типа указателя, производные от new-type-id или type-id. Программа использует этот указатель для доступа к новому объекту, которому выделена память.

Оператор new вызывает функцию operator new. Для массивов любого типа и для объектов, которые не classявляются , structили union типами, глобальной функцией, ::operator newвызывается для выделения хранилища. Объекты типа класса могут определять собственную operator new статическую функцию-член на основе каждого класса.

Когда компилятор обнаруживает new оператор для выделения объекта типаT, он выдает вызов T::operator new( sizeof(T) ) или, если пользователь не определенoperator new. ::operator new( sizeof(T) ) Это то, как new оператор может выделить правильный объем памяти для объекта.

Примечание.

Аргумент operator new типа std::size_t. Этот тип определяется в <direct.h>, <malloc.h, <memory.h>, search.h>><, <stddef.h>, <stdio.h>, stdlib.h>, <<string.h> и <time.h.>

Параметр в грамматике разрешает спецификацию new-placement (см. грамматику оператораnew). Параметр new-placement можно использовать только для определяемых пользователем реализаций operator new; он позволяет передавать operator newдополнительные сведения. Выражение с таким полем new-placement , как T *TObject = new ( 0x0040 ) T; преобразование T *TObject = T::operator new( sizeof( T ), 0x0040 ); в значение, в которое входит operator newкласс T, в противном случае — в T *TObject = ::operator new( sizeof( T ), 0x0040 );.

Первоначальное new-placement намерение поля заключается в том, чтобы разрешить аппаратным зависимым объектам выделяться по указанным пользователем адресам.

Примечание.

Хотя в предыдущем примере показано только один аргумент в new-placement поле, нет ограничений на то, сколько дополнительных аргументов можно передать таким operator new образом.

Даже если operator new для типа Tкласса определен тип класса, можно явно использовать глобальный оператор new , как в следующем примере:

T *TObject = ::new TObject;

Оператор область разрешения (::) принудительно использует глобальный new оператор.

См. также

Выражения с унарными операторами
Ключевые слова
new операторы и delete операторы