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

Оператор «размещение нового» объявляется так:

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 байта, но вы указали местоположение, которое не выровнено должным образом, у вас может быть серьезное бедствие.

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

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

4

Другие решения

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

Это подразумевает, что строительство никогда не выполняется самой функцией распределения. Функция выделения имеет странное имя 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;), он позволяет явно вызывать конструктор для объекта, который конструируется в заданном месте памяти. Этот вызов функции может быть устранен компилятором, поэтому никаких дополнительных затрат не возникает.

2

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

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

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

0

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

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

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

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

0
По вопросам рекламы [email protected]