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)...);
}
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:
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.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With