Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::allocator_traits::construct with const pointer

Tags:

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

like image 462
Andreas Pasternak Avatar asked Jul 08 '19 20:07

Andreas Pasternak


1 Answers

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.

like image 148
Deduplicator Avatar answered Oct 02 '22 13:10

Deduplicator