Let's imagine we have some class
struct Foo {
constexpr Foo(int& x) : x_(x) { x_++; }
constexpr ~Foo() noexcept { x_++; }
int& x_;
};
In C++20 with g++-10 -std=c++20 we can have a function like this:
constexpr int do_foo_1() {
int x = 0;
Foo* p = new Foo(x);
delete p;
return x;
}
int main() {
static_assert(do_foo_1() == 2);
}
Let's try to divide operator new into memory allocation and inplace construction.
So new function looks like this:
constexpr int do_foo_2() {
int x = 0;
Foo* p = static_cast<Foo*>(::operator new(sizeof(Foo)));
p = ::new ((void*) p) Foo(x);
p->~Foo();
::operator delete(p);
return x;
}
But now there are two errors: our memory allocation new and placement new are not constexpr!
error: call to non-‘constexpr’ function ‘void* operator new(std::size_t)’
error: call to non-‘constexpr’ function ‘void* operator new(std::size_t, void*)’
So let's try to work around these errors. With <memory> we can have code like this:
constexpr int do_foo_3() {
std::allocator<Foo> alc;
int x = 0;
Foo* p = alc.allocate(1);
p = std::construct_at(p, x);
std::destroy_at(p);
alc.deallocate(p, 1);
return x;
}
int main() {
static_assert(do_foo_3() == 2);
}
Question
What is the difference between my usage and usage of these operators in standard library?
Isn't the same thing happens in std::construct_at and std::allocator<Foo>::allocate under the hood?
Note
I tried to replicate std::construct_at by simply copying it implementation from <stl_construct.h> but I got same error:
error: ‘constexpr decltype (...) my_construct_at(_Tp*, _Args&& ...) [...]’ called in a constant expression
error: call to non-‘constexpr’ function ‘void* operator new(std::size_t, void*)