The following code compiles fine:
#include <iostream>
#include <memory>
int main()
{
const int * a = new int(5);
std::cout << *a << std::endl; // Prints 5
// *a = 5; // Compiler error.
using at = std::allocator_traits<typename std::allocator<int>>;
auto alloc = std::allocator<int>();
at::construct(alloc, a);
std::cout << *a << std::endl; // Prints 0
}
Under the hood libstdc++ does
::new((void*)a) int;
but a
is const
!
Is this undefined behavior? Or does placement new not count as modifying?
I modified the value of *a
, which is const. To my understanding this is not allowed:
Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue results in undefined behavior.
https://en.cppreference.com/w/cpp/language/const_cast
TL;DR: Fine until C++2a, thereafter std::allocator_traits<std::allocator<int>>::construct()
will be more demanding of the passed pointer.
Well, std::allocator_traits::construct()
uses static_cast<void*>
since it was introduced, unless the allocator provides it.
And while std::allocator::construct()
was deprecated in C++17 and will be removed in C++2a, it always used a c-style cast.
Thus, it's syntactically valid until C++2a.
And as the pointed-to object itself is not const
, only the pointer it is accessed through having that qualifier, casting away const
and modifying is perfectly legal.
As the pseudo-dtor for int
is trivial, it doesn't even matter that it isn't called before constructing a new one on top of it.
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