Размещение новых и исключений

Оператор размещения новых объявлен так:

void* operator new (std::size_t size, void* ptr) noexcept;

Но хотя это и не связано с каким-либо фактическим распределением, поэтому исключаются недопустимые исключения при распределении, все же возможно, что указатель указывает на неправильное местоположение, и в этом случае можно ожидать получения ошибки диапазона или переполнения / переполнения, но не будет тот факт, что он был объявлен noexcept вместо этого просто прекратить выполнение?

Также это означает, что до размещения C++11 new сгенерирует и попытается обработать std::unexpected в случае std::set_unexpected вместо прямого сбоя?

Разве не должно быть перегрузки броска размещения, нового "на всякий случай"?

4 ответа

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

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

Отредактировано в ответ на комментарии:-

#include <new>        // Must #include this to use "placement new"
#include "Fred.h"     // Declaration of class Fred

    void someCode()
    {
      char memory[sizeof(Fred)];     // Line #1     //Allocate enough memory.
      void* place = memory;          // Line #2     // There's no need for this.

      Fred* f = new(place) Fred();   // Line #3 (see "NOTE" below)
      // The pointers f and place will be equal

      ...
    }

ПРИМЕЧАНИЕ. Вы берете на себя полную ответственность за то, что указатель, который вы передаете оператору "размещения нового", указывает на область памяти, которая достаточно велика и правильно выровнена для создаваемого вами типа объекта. Ни компилятор, ни система времени выполнения не предпринимают никаких попыток проверить, правильно ли вы это сделали. Если ваш класс Fred должен быть выровнен по 4-байтовой границе, но вы указали местоположение, которое не выровнено должным образом, у вас может быть серьезное бедствие.

Короче говоря, это означает, что вы должны быть осторожны с использованием размещения новых ИЛИ, если ваш парень, как я, то никогда не используйте его:)

Надеюсь, это очистит ваши сомнения.

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

Это подразумевает, что построение никогда не выполняется самой функцией распределения. Функция выделения имеет странное имя operator new,

Можно предоставить дополнительные параметры для функции выделения, используя синтаксис размещения-новый:

new int(5)        // non-placement form
new(1,2,3) int(5) // placement-form

Тем не менее, размещение нового обычно относится к очень конкретному выражению нового:

void* address = ...;
::new(address) int(5) // "the" placement-form

Эта форма предназначена для создания объекта в уже выделенной области памяти, т. Е. Она предназначена просто для вызова конструктора, но не для выполнения какого-либо выделения.

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

void* operator new (std::size_t size, void* ptr) noexcept;

Быть неоператором (return ptr;), он позволяет явно вызывать конструктор для объекта, который конструируется в заданном месте памяти. Этот вызов функции может быть исключен компилятором, поэтому никаких дополнительных затрат не возникает.

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

Вы можете написать свой собственный, который проверяет его ввод.

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

Кажется, вы думаете, что функция может как-то проверять указатель, который ей передают.

Это не может. В стандарте языка нет ничего, что позволяло бы это. Конечно, проверка на случай nullptr возможна, но только незначительно полезна.

Ошибки выравнивания строго UB, поэтому любая реализация может делать все что угодно. (даже просто это работает: x86)

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

Другие вопросы по тегам