This is very similar to Correct usage of placement-new and explicit destructor call but tighter in scope:
If I have a type, S
, for which std::is_nothrow_default_constructible_v<S>
and std::is_nothrow_destructible_v<S>
and not std::has_virtual_destructor_v<S>
and not std::is_polymorphic_v<S>
, is it defined behavior to call this function?:
template <typename T>
void reconstruct(T& x) noexcept {
// C++20: requires instead of static_assert:
static_assert(std::is_nothrow_default_constructible_v<T>);
static_assert(std::is_nothrow_destructible_v<T>);
static_assert(!std::has_virtual_destructor_v<T>);
static_assert(!std::is_polymorphic_v<T>);
x.~T();
::new (&x) T{};
}
What if there are existing pointers or references to, as in
int main() {
S s;
s.x = 42;
const S& sref = s;
reconstruct(s);
return sref.x; // Is this UB because the original S sref references no longer exists?
}
My reason to ask this is that std::once_flag
has no reset mechanism. I know why it generally can't and it would be easy to misuse, however, there are cases where I'd like to do a thread-unsafe reset, and I think this reconstruction pattern would give me what I want provided this reconstruction is defined behavior.
https://godbolt.org/z/de5znWdYT
== false` as well.– Spencer Jul 07 '22 at 18:47