Why is `std::deque` not `constexpr` friendly?
Asked Answered
T

1

6

I'm learning the c++ STL and it came to my attention that while most functionalities supported by std::vector and std::array (contiguous storage) are marked with constexpr, that's not the case for std::deque and other non-contiguous storages. So I spent some time doing some research, I found a proposal in 2019, Making std::deque constexpr, and std::deque still has not implemented constexpr for its methods.

My confusion is that std::array guarantees that its elements are stored on the stack; just like a normal C-style array, so it should be computed at compile time, but std::vector allocates memory on the heap so if it's evaluated at compile time, so is deque, right?

Thanks!

Tanto answered 28/6, 2022 at 0:42 Comment(1)
The answer really is: that's more work than it's worth.Truant
E
5

According to https://github.com/cplusplus/papers/issues/665 which keeps a log of the progression of the proposal through the standards committee process, there seem to have been some doubts whether a constexpr std::deque can be implemented without core language changes.

Unfortunately it doesn't say what the specific concern is. Probably some common implementation makes use of some language construct that specifically is not allowed in constant expressions or the implementation relies on some construct that is undefined behavior according to the standard. The latter is usually not a problem for the standard library, since it is not bound by the language rules and can make assumptions about the particular compiler's behavior. However in constant expressions core language undefined behavior is always a hard error and therefore such constructs might often not be usable in constant expression contexts without introducing magic compiler workarounds.

As mentioned in the linked github issue, there seem to also be some library facilities which need to have constexpr added to make this work as well.

Aside from such issues, generally, I don't think there is any reason to not make all containers and container adaptors constexpr-friendly now that std::allocator can be used in constant expressions. They probably just want to make sure that they can be properly implemented as constexpr first. My guess is that for the same reason only std::string and std::vector were done with C++20, since these are the simplest and most important allocator-aware containers to apply constexpr to. (std::array has been constexpr for longer since it doesn't require any dynamic allocations.)

Although, looking at the date of the last entry in the issue (as well as the accompanying issues for std::list, std::priority_queue, etc.) it seems to not have progressed in the last two years, maybe because the author of the proposal did not pursue it further, but I can't really tell.


In either case, when we say that std::vector (or other allocator-aware containers) are constexpr-friendly, this means something else than it does for e.g. std::array. You can declare a constexpr std::array variable and use it as you would use a const std::array variables, but you can't declare a constexpr std::vector variable (generally at all) and use it as you would a const std::vector.

What you can do however is use a std::vector variable in e.g. a constexpr function to do some calculations, as long as the variable is created after the evaluation of the constant expression starts and is destroyed before it ends. Currently this is not possible with e.g. a std::list which is not constexpr-friendly.

The reason for this is that the compiler will not actually allocate memory at compile-time for the container and then transfer it in some way into a runtime allocation (whether static or dynamic). Instead dynamic allocations at compile-time are separate from runtime ones and must be deallocated before the constant expression evaluation in which they were allocated ends.

Enact answered 28/6, 2022 at 0:55 Comment(4)
Thank you so much for your detailed information. "I don't think there is any reason to not make all containers and container adaptors constexpr-friendly" -- This is the main reason I was wondering about the STL. Like I mentioned above, I understand that std::array is constant-expression friendly because it's computed at compile time. I also look at the source code of both vector and deque and it seems to me that they both use std::allocator internally to handle memory management. So I just want to know why most methods in vector are constexpr but those in deque are not.Tanto
@Yuuta Dynamic allocations via std::allocator are only constexpr-friendly since C++20. When that change was made it became possible to make containers using it also constexpr-friendly. At the very least to make a class constexpr-friendly you need to put constexpr on most or all member functions and that is what would be the main change in the C++ standard which governs the language. But putting constexpr on a function is not always enough to make it work.Enact
For a simple example reinterpret_cast is forbidden in constant expressions, so it can't be used in member function definitions if the class is supposed to be constexpr-friendly. Before the standards committee can add constexpr it must be convinced that the standard library implementers can make their current implementations of the container to allow constexpr without major issues. The process of making sure of that takes some time and work and seems to have simply stalled for std::deque. From what I can tell in the link, it originally looked like it could have made it for C++23.Enact
@Yuuta Also look at the polls in the link such as "We should promise more committee time to pursuing [these proposals] knowing that our time is scarce and this will leave less time for other work." with some votes against. It shows that there is also simply an issue of prioritizing which language features to spend time working on. Other more significant library types also haven't been constexpr-friendly and require committee time, for example std::unique_ptr which has been made constexpr-friendly recently for the C++23 draft (github.com/cplusplus/papers/issues/961).Enact

© 2022 - 2024 — McMap. All rights reserved.