Поиск…


Синтаксис

  • : :( opt ) new ( выражение-list ) ( opt ) new-initial-initial -initial-initializer ( opt )
  • : :( opt ) new ( expression-list ) ( opt ) ( type-id ) new-initializer ( opt )
  • : :( opt ) delete cast-expression
  • : :( opt ) delete [] cast-expression
  • std :: unique_ptr < type-id > var_name (новый тип-идентификатор ( opt )); // C ++ 11
  • std :: shared_ptr < type-id > var_name (новый тип-идентификатор ( opt )); // C ++ 11
  • std :: shared_ptr < type-id > var_name = std :: make_shared < type-id > ( opt ); // C ++ 11
  • std :: unique_ptr < type-id > var_name = std :: make_unique < type-id > ( opt ); // C ++ 14

замечания

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

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

Выделенный тип обычно явно указан, например, new Foo , но также может быть записан как auto (начиная с C ++ 11) или decltype(auto) (начиная с C ++ 14), чтобы вывести его из инициализатора.

Инициализация выделенного объекта происходит по тем же правилам, что и инициализация локальных переменных. В частности, объект будет инициализирован по умолчанию, если инициализатор iso опущен, а при динамическом распределении скалярного типа или массива скалярного типа нет гарантии, что память будет обнулена.

Объект массива, созданный новым выражением, должен быть уничтожен с помощью delete[] , независимо от того, было ли новое выражение написано с помощью [] или нет. Например:

using IA = int[4];
int* pIA = new IA;
delete[] pIA;  // right
// delete pIA;  // wrong

стек

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

int main() {
    int a = 0; //Stored on the stack
    return a;
}

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

float bar() {
    //f will be placed on the stack after anything else
    float f = 2;
    return f;
}

double foo() {
    //d will be placed just after anything within main()
    double d = bar();
    return d;
}

int main() {
    //The stack has no user variables stored in it until foo() is called
    return (int)foo();
}

Данные, хранящиеся в стеке, действительны только до тех пор, пока область, которая распределяет переменную, все еще активна.

int* pA = nullptr;

void foo() {
    int b = *pA;
    pA = &b;
}

int main() {
    int a = 5;
    pA = &a;
    foo();
    //Undefined behavior, the value pointed to by pA is no longer in scope
    a = *pA;
}

Свободное хранение (куча, динамическое распределение ...)

Термин «куча» представляет собой общий вычислительный термин, означающий область памяти, из которой части могут быть выделены и освобождены независимо от памяти, предоставленной стеком .

В C++ Стандарт относится к этой области как к свободному магазину, который считается более точным.

Области памяти, выделенные из Free Store, могут жить дольше, чем исходная область, в которой она была выделена. Данные, слишком большие для хранения в стеке, также могут быть выделены из Free Store .

Сырая память может быть выделена и освобождена новыми и удаляемыми ключевыми словами.

float *foo = nullptr;
{
    *foo = new float; // Allocates memory for a float
    float bar;              // Stack allocated 
} // End lifetime of bar, while foo still alive

delete foo;          // Deletes the memory for the float at pF, invalidating the pointer
foo = nullptr;       // Setting the pointer to nullptr after delete is often considered good practice

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

// Allocates memory for an array of 256 ints
int *foo = new int[256];
// Deletes an array of 256 ints at foo
delete[] foo;

При использовании new и delete вместо malloc и free , конструктор и деструктор будут выполняться (подобно объектам на основе стека). Поэтому новые и удалить, предпочитаемые над таНосом и бесплатно.

struct ComplexType {
    int a = 0;

    ComplexType() { std::cout << "Ctor" << std::endl; }
    ~ComplexType() { std::cout << "Dtor" << std::endl; }
};

// Allocates memory for a ComplexType, and calls its constructor
ComplexType *foo = new ComplexType();
//Calls the destructor for ComplexType() and deletes memory for a Complextype at pC
delete foo;
C ++ 11

Начиная с C ++ 11, для указания владельца рекомендуется использовать интеллектуальные указатели .

C ++ 14

C ++ 14 добавил std::make_unique в STL, изменив рекомендацию в пользу std::make_unique или std::make_shared вместо того, чтобы использовать голый новый и удалить .

Размещение новых

Бывают ситуации, когда мы не хотим полагаться на Free Store для выделения памяти, и мы хотим использовать пользовательские выделения памяти, используя new .

В этих ситуациях мы можем использовать Placement New , где мы можем сказать оператору «new» выделить память из предварительно выделенной ячейки памяти

Например

int a4byteInteger;

char *a4byteChar = new (&a4byteInteger) char[4];

В этом примере память, a4byteChar представляет собой 4 байта, выделенных для «стека» с помощью целочисленной переменной a4byteInteger .

Преимущество такого распределения памяти заключается в том, что программисты контролируют распределение. В приведенном выше примере, поскольку a4byteInteger выделяется в стеке, нам не нужно делать явный вызов «delete a4byteChar».

Такое же поведение может быть достигнуто и для динамически распределенной памяти. Например

int *a8byteDynamicInteger = new int[2];

char *a8byteChar = new (a8byteDynamicInteger) char[8];

В этом случае указатель на память a8byteChar будет ссылаться на динамическую память, выделенную a8byteDynamicInteger . В этом случае, однако, нам нужно явно вызвать delete a8byteDynamicInteger для освобождения памяти

Другой пример для класса C ++

struct ComplexType {
    int a;

    ComplexType() : a(0) {}
    ~ComplexType() {}
};

int main() {
    char* dynArray = new char[256];

    //Calls ComplexType's constructor to initialize memory as a ComplexType
    new((void*)dynArray) ComplexType();

    //Clean up memory once we're done
    reinterpret_cast<ComplexType*>(dynArray)->~ComplexType();
    delete[] dynArray;

    //Stack memory can also be used with placement new
    alignas(ComplexType) char localArray[256]; //alignas() available since C++11

    new((void*)localArray) ComplexType();

    //Only need to call the destructor for stack memory
    reinterpret_cast<ComplexType*>(localArray)->~ComplexType();

    return 0;
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow