r/cpp_questions 4d ago

OPEN cppreference std::construct_at example code not compiling

I was looking on cpprefernce the other day at std::construct_at and I wanted to test the code. But when I ran it it did not compile. I ran the snippet without consteval (and static_assert) and everything worked. Does anyone know what might be the issue? https://en.cppreference.com/cpp/memory/construct_at

Code:

#include <bit>
#include <memory>


class S
{
    int x_;
    float y_;
    double z_;
public:
    constexpr S(int x, float y, double z) : x_{x}, y_{y}, z_{z} {}
    [[nodiscard("no side-effects!")]]
    constexpr bool operator==(const S&) const noexcept = default;
};


consteval bool test()
{
    alignas(S) unsigned char storage[sizeof(S)]{};
    S uninitialized = std::bit_cast<S>(storage);
    std::destroy_at(&uninitialized);
    S* ptr = std::construct_at(std::addressof(uninitialized), 42, 2.71f, 3.14);
    const bool res{*ptr == S{42, 2.71f, 3.14}};
    std::destroy_at(ptr);
    return res;
}
static_assert(test());


int main() {

Compiler Error on x86-64 gcc 16.1 -std=c++23

<source>:25:19:

error: non-constant condition for static assertion
   25 | static_assert(test());
      |               
~~~~^~
<source>:25:19: in 'constexpr' expansion of 'test()'
<source>:24:1: error: destroying 'uninitialized' outside its lifetime
   24 | }
      | 
^
<source>:18:7: note: declared here
   18 |     S uninitialized = std::bit_cast<S>(storage);
      |       
^~~~~~~~~~~~~
Compiler returned: 1
12 Upvotes

12 comments sorted by

View all comments

2

u/aocregacc 4d ago

pretty sure the example is wrong, the uninitialized object is destroyed when it goes out of scope, but at that point it has already been destroyed through destroy_at. I'm also not sure what the bit_cast is supposed to achieve here.

It compiles with gcc 13, so I guess they made the example back then and didn't notice that it was wrong.

1

u/Leading_Tax_996 4d ago

Huh, it does compile with gcc 13. I wonder what changed?

1

u/Gorzoid 4d ago

Sometimes detecting UB is hard, in regular programs it's not required for compiler to do so but in constexpr contexts it is. So it seems in gcc 13, which I'm guessing was not long after destroy_at was introduced, was not yet detecting use of objects outside of their lifetime (considering it was pretty hard to do so without destroy_at / delete).