6

4th Edit: the original question title is:

Why constexpr specifier is not allowed for non-empty std::vector?

This title, as @Barry points out, is a duplicate to C++20 constexpr vector and string not working. But there is a difference in my question description: I am allocating constexpr vector in consteval function instead of normal runtime function or constexpr function.

I understand that during compile-time computing, only transient allocation is allowed, as @Barry answered in the linked question.

What I was confused about is that: for consteval function:

  1. any of its local variables will be dealloacted after it returns
  2. it only returns in compile-time, since it will only be called in compile-time
  3. so constexpr vector, as a local variable, will be deallocated in compile-time
  4. then why is it not allowed?

And my other edits below answered this confusion.

-----------------Below is the orignal question description----------

Why the following code does not compile:

consteval int foo() {
  constexpr std::vector<int> vec{1};
  return vec[0];
}

As I learned, std::vector and std::string can be used in compile time as long as both the allocation and deallocation happens in compile time. And if I delete the constexpr specifier, this code will compile.

But adding constexpr still does not violate this rule, right? Why is it not allowed?

I got this error when compiled with gcc 13 but I don't understand it:

/opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/allocator.h:195:52: error:
'std::vector<int>(std::initializer_list<int>{((const int*)(& const int [1]{1})), 1}, std::allocator<int>())' is not a constant expression because it refers to a result of 'operator new'
  195 |             return static_cast<_Tp*>(::operator new(__n));
      |                  

Edit: My question is not a duplicate to any other questions. There is only one duplicate constexpr specifier on std::vector doesn't work, but with wrong answer about why constexpr is not allowed: it states that "compile-time std::vector should be allocated and deallocated in compile-time, so it is not allowed", but the code above does not violate this rule.

2nd Edit: Thanks for answers from @user4581301 and @chris. I learned that I got a wrong understanding of a rule:

Wrong: it will be fine if memory allocated via new in compile-time is deleted also in compile-time.

Correct: in compile-time, memory allocated via new must be deleted in the same constant expression context.

And the answer to my question is that constexpr vector<int> will introduce a new constant expression context while vector<int> does not.

3rd Edit: What are the conditions that `constexpr` will start a new constant expression context?

11
  • 2
    You have to read between the lines a bit. After constexpr std::vector<int> vec{1}; a dynamic allocation, the one inside vec, would still be alive after the constant expression, and that's a no-no. Commented Jul 26, 2023 at 20:49
  • @user4581301 But std::vector<int> is a local variable, it will be deallocated when it goes out of scope, right? And it cannot be alive in any run time context since it is consteval function. Also, even without constexpr, it is still dynamic allocation, why does it compile without constexpr? Commented Jul 26, 2023 at 20:51
  • 1
    vec is automatically allocated, but it contains inside it a pointer to a dynamically allocated array (and a couple book-keeping variables). that internal array must not exist after the constant expression, constexpr std::vector<int> vec{1};, but there it is still alive on the next line at return vec[0];. Commented Jul 26, 2023 at 20:55
  • 4
    @Waker, Making the variable constexpr starts a new context. It's this context that the allocation escapes. Picture (conceptually) the compiler spinning up a new interpreter for evaluating a foo call, and then spinning up another new interpreter from the first one for the constexpr line. If you remove the constexpr, you're still in the first interpreter. Commented Jul 26, 2023 at 20:56
  • 1
    Regardless, great question. One of those rare duplicates deserving of an upvote. May it live long as a useful landing page. Commented Jul 26, 2023 at 20:58

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.