Может ли размещение new (выражение) вызывать, если конструктором объекта является noexcept?

#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 выражения система выполняет ровно две вещи:

  1. Он вызывает соответствующую версию operator new() для получения памяти. Если выделение памяти завершается неудачно, оно должно выбрасывать std::bad_alloc значение operator new() без noexcept уточнения и возвращать nullptr в противном случае.
  2. Если возвращается не- nullptr , выражение затем вызывает конструктор типа в new выражении. Если эта конструкция завершается ошибкой с исключением, operator delete() вызывается сопоставление вызываемого operator new() с результатом этого operator new() .

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

Комментарии:

1. Я думаю, вопрос в том, делает ли новое выражение что-нибудь еще, что может выбросить помимо вызова конструктора

2. Единственное, что делает вызов размещения new, — это вызывает указанное выше operator new() , за которым следует вызов конструктора объекта в new выражении (и это вызовет сопоставление operator delete() , если конструкция выдает исключение).

3. Выражение placement new также проверяет адрес, возвращенный с помощью operator new against nullptr перед вызовом конструктора. Конечно, в данном случае это не будет иметь значения, но это полезно помнить.

4. Что, если фактические аргументы, переданные для Obj<T>::Obj требования определенного пользователем преобразования, могут вызвать сбой?

5. @JamesKanze затем конструктор выбрасывает… Я думаю