https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110057
--- Comment #18 from user202729 <user202729 at protonmail dot com> --- (In reply to Jonathan Wakely from comment #17) > I don't think that optimization would be valid. Users could do disgusting > things like this (as long as sizeof(Base) == sizeof(Derived)): > > std::vector<Base> v(1); > v[0].~Base(); > ::new((void*)v.data()) Derived(); > v[0].f(); > v[0].~Derived(); > ::new((void*)v.data()) Base(); According to "n.m." on StackOverflow, that code is illegal https://stackoverflow.com/questions/76380436/is-placement-new-of-derived-type-within-a-vector-array-of-base-type-legal#comment134688951_76380436 So I guess we're safe if the comment is correct. (Same for the vector destructor case) > This certainly seems to be allowed: > > std::vector<Base> v(1); > Base* p = v.data(); > p->~Base(); > ::new((void*)p) Derived(); > p->f(); > p->~Derived(); > ::new((void*)p->) Base(); The clause seems to apply just as well, you cannot access the newly constructed `Derived` object through `p`. Further reading: https://stackoverflow.com/questions/62642542/were-all-implementations-of-stdvector-non-portable-before-stdlaunder > If we can be sure that v[0] requires the static and dynamic types to match, > then we could do something like: > > reference > operator[](size_type __n) _GLIBCXX_NOEXCEPT > { > __glibcxx_requires_subscript(__n); > #ifdef __cpp_rtti > if (typeid(this->_M_impl._M_start[__n]) != typeid(value_type)) > __builtin_unreachable(); > #endif > return *(this->_M_impl._M_start + __n); > } > > I have no idea whether that would help anything, or if the use of typeid > would actually pessimize things. It turns out that the compiler can currently prove (with optimization enabled) that `typeid::operator==` is pure, so it wouldn't pessimize things. If you want to be extra careful I suppose `#if __OPTIMIZE__` is an option.