Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can placement new (expression) throw if the constructor of the object is 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(Args&&... args) { // my constructor
    // placement new: construct the value in the statically allocated space
    new (&value_pod_) T(std::forward<Args>(args)...); // <- can this whole expression throw if the constructor of T doesn’t throw?
  }
}

Normal new can throw if the allocation fails or if the construction fails (correct me if there are other cases), but since placement new doesn’t allocate any space, can the new expression throw if the constructor of T doesn’t throw?

I.e. is the following noexcept specification correct and safe?

Obj(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
  new (&value_pod_) T(std::forward<Args>(args)...);
}
like image 773
bolov Avatar asked Jun 17 '14 14:06

bolov


1 Answers

The placement new from <new> is declared to be noexcept according to 18.6 [support.dynamic] paragraph 1:

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

When using a new expression the system does exactly two things:

  1. It calls the appropriate version of the operator new() to obtain memory. If memory allocation fails it should throw std::bad_alloc for an operator new() without a noexcept qualification and return nullptr otherwise.
  2. If a non-nullptr is returned, the expression then calls the constructor of the type in the new expression. If this construction fails with an exception, the operator delete() matching the called operator new() is called with the result from that operator new().

Since memory allocation can't fail, the only option to get an exception is from the constructor of the type.

like image 79
Dietmar Kühl Avatar answered Sep 29 '22 12:09

Dietmar Kühl