#c #exception #c 11 #placement-new #noexcept
#c #исключение #c 11 #размещение-новое #noexcept
Вопрос:
template <class T>
struct Obj {
// Plain Old Data for T
using InternalPod = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
InternalPod value_pod_;
template<class... Args>
Obj(Argsamp;amp;... args) { // my constructor
// placement new: construct the value in the statically allocated space
new (amp;value_pod_) T(std::forward<Args>(args)...); // <- can this whole expression throw if the constructor of T doesn’t throw?
}
}
Обычный new
может выбрасываться, если выделение завершается неудачно или если построение завершается неудачно (поправьте меня, если есть другие случаи), но поскольку размещение new не выделяет никакого пространства, может ли новое выражение выбрасывать, если конструктор T
не выбрасывает?
Т.е. Является ли следующая noexcept
спецификация правильной и безопасной?
Obj(Argsamp;amp;... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
new (amp;value_pod_) T(std::forward<Args>(args)...);
}
Комментарии:
1. Все
operator new
, что делает размещение, возвращает переданный указатель, так что нет, само размещение new не может выбрасывать.2. @Simple: размещение new, безусловно, может выбрасывать, но только если создаваемый объект выбрасывает его конструктор.
3. @Mankarse верно,
new
выражение в целом может, ноoperator new
не делает.4. Меня интересует выражение в целом
5. Вам следует отредактировать свой вопрос, чтобы прояснить это.
Ответ №1:
Размещение new
from <new>
объявлено в noexcept
соответствии с пунктом 1 18.6 [support.dynamic]:
…
void* operator new (std::size_t size, void* ptr) noexcept;
…
При использовании new
выражения система выполняет ровно две вещи:
- Он вызывает соответствующую версию
operator new()
для получения памяти. Если выделение памяти завершается неудачно, оно должно выбрасыватьstd::bad_alloc
значениеoperator new()
безnoexcept
уточнения и возвращатьnullptr
в противном случае. - Если возвращается не-
nullptr
, выражение затем вызывает конструктор типа вnew
выражении. Если эта конструкция завершается ошибкой с исключением,operator delete()
вызывается сопоставление вызываемогоoperator new()
с результатом этогоoperator new()
.
Поскольку выделение памяти не может завершиться ошибкой, единственный вариант получить исключение — из конструктора типа.
Комментарии:
1. Я думаю, вопрос в том, делает ли новое выражение что-нибудь еще, что может выбросить помимо вызова конструктора
2. Единственное, что делает вызов размещения new, — это вызывает указанное выше
operator new()
, за которым следует вызов конструктора объекта вnew
выражении (и это вызовет сопоставлениеoperator delete()
, если конструкция выдает исключение).3. Выражение placement new также проверяет адрес, возвращенный с помощью
operator new
againstnullptr
перед вызовом конструктора. Конечно, в данном случае это не будет иметь значения, но это полезно помнить.4. Что, если фактические аргументы, переданные для
Obj<T>::Obj
требования определенного пользователем преобразования, могут вызвать сбой?5. @JamesKanze затем конструктор выбрасывает… Я думаю