For earlier C++ standard versions the final drafts before ISO standardization are hosted at https://github.com/timsong-cpp/cppwp . The paid ISO standardized version is supposedly not meaningfully different.
Relevant parts of the standard (C++20):
* pop_back: https://timsong-cpp.github.io/cppwp/n4868/containers#tab:con... "Preconditions: a.empty() is false."
* Meaning of "precondition": https://timsong-cpp.github.io/cppwp/n4868/library#structure....
Reading the standard can be quite a challenge. The standard tries to not repeat itself, which often means that you don't get your answer in a self-contained paragraph, but you have to hunt down cross-references and definitions.
As a C++ language reference I highly recommend https://en.cppreference.com .
edit:
In this case https://en.cppreference.com/w/cpp/container/vector/pop_back is super clear. Basically everything you want to know about the function in three sentences:
> Removes the last element of the container. Calling pop_back on an empty container results in undefined behavior. Iterators and references to the last element, as well as the end() iterator, are invalidated.
I'd be careful about such re-formulations of the Standard. When I was adding printf format checking to the D compiler, I discovered there were subtle discrepancies in the description of exactly how printf behaves. I went back to using the Standard.
And surely the stakes are different when you are writing a compiler compared to just using the language. As a user if you are not sure about certain parts of the language then you are free to steer away from those parts. As an implementer, you are not free to not implement parts of the standard.
Seems like it would be easy to implement and undefined behavior is not something that backwards compatibility forces you to keep.
I was thinking just the same as a bunch of you. If I were implementing a container class, I would include this check. Probably some do. It can't be relied on.
There is no generally meaningful way to recover from an error condition like this, which in its nature is a logical mistake in your code. And that's the reason why I think std::vector won't throw an exception but will give you an opt-in to terminate the process through the assert.
I think it's not about the performance, although it can be argued, but it's more fundamental code design problem.
Crash. Crashing is a million times better than undefined behaviour, which can and often does include carrying on computing with incorrect data.
Also, aborting the program is not something you can universally apply. For some it works well for others not so much. Most recent example being the rust in the kernel which, well, tries to take this sort of a purist approach, however, real world doesn't work that way.
This is just how C++ works: performance over safety, safety is semi-possible but requires a bunch of opt-ins. And the parts needed for safe C++ aren't standardized, so good luck if you're using multiple compilers.
Now, adding a check is adding several other operations, including a conditional branch.
This is fairly bad for performance. So the C++ way is that you write the check yourself if your code requires it.
Then there can't be a pop without a push or some other operation that filled the vector, and that operation necessarily has the checks and branches to allocate more space if necessary.
The compiler should also be smart enough to branch forward to the throw so the branch predictor assumes not taken by default, so this is still cheap af.
This is "fairly bad" for performance maybe 1% of the time. For the other 99%, you'd make pop_back check and throw and keep the unchecked version as pop_back_fast or something like that. That's what a sane API would look like.
This is a complicated cost model which compilers usually avoid.
>The compiler should also be smart enough.
It isn't.
> That's what a sane API would look like.
Awesome, there is nothing stopping you from creating your own functions which add this check.
It definitely is. Go try it on godbolt.
> Awesome, there is nothing stopping you from creating your own functions which add this check.
Thanks for your amazing insight.
STL is lacking? Nothing is stopping us from writing our own functions.
STL is garbage? Nothing is stopping us from writing our own replacement.
The whole language is garbage? Nothing is stopping us from creating a new one from scratch.
Really, you've found the solution to everything.
There's a dark irony in the fact that programmers do this all the time.
https://github.com/microsoft/STL/blob/main/stl/inc/vector#L1...
Whatever _STL_VERIFY does, pop_back can't throw, as it's marked noexcept.
EA STL: https://github.com/electronicarts/EASTL/blob/master/include/...
Default assertion handler seems to set up a debug break point: https://github.com/electronicarts/EASTL/blob/29a805e4d83d7dd...
Macro defined somewhere here: https://github.com/electronicarts/EASTL/blob/76d6842d5d833c0...
Does not seem to throw, but a lot of this is user-configurable.
I'm sure I still didn't cover all implementations. You are free to point out a single one that throws on pop_back. Or just ask ChatGPT which implementation throws.
One example is not a guarantee, but the experience made my day, and probably my week. Which is why the pop_back() thing made me worry :)
“Boom that was it” _if_ you blindly trust ChatGPT to generate correct code. If you don’t (and IMO you shouldn’t), “it worked for me today” isn’t sufficient to decide whether you can trust it.
You should go to the documentation of that package, judge whether ChatGPT used it correctly (and yes, that involves looking up the idiosyncrasies of function calls), judge whether you trust that package, evaluate its license, etc.
When a prompt is “analytic” in nature, that is contains the facts required for the output, like “convert this following box score into an entertaining account of the baseball game it describes”, it works rather well.
When the prompt is “synthetic” in nature, when it doesn’t have the facts in the prompt, like “based on that same box score, provide some direct quotes from the broadcasters”, it does not reliably provide factual responses.
* when
A chat bot looks like a great help to parse through huge volumes of documentation.
If the chatbot built around the docs outputs garbage, that is a telltale sign that the documentation was garbage to start with.
Just because people started developing clever chatbots that misfire, let's not fool ourselves into believing documentation was a solved problem and all docs were squeaky clean.
That’s not how the chat bot works. This particular chat bot can be trained on a bunch of documents and still tell you something that contradicts the facts that are clear to a human in one of the said documents.
It’s a known phenomenon called “hallucination” and this actually gives the chat bot, to some extent, it’s ability to imitate creativity (to put it simply).
edit: typo
>If the container is not empty, the function never throws exceptions (no-throw guarantee). Otherwise, it causes undefined behavior.
ChatGPT failed at basic regurgitation.
How about this:
If the container is empty the function causes undefined behaviour. Otherwise it never throws exceptions (no-throw guarantee).
We avoided having to hold two negatives, and we also put the thing you need to care about up front where it's more likely to be noticed.
The C++ (draft) standard is on GitHub! [0] Compiling it needs Perl and some LaTeX packages, but is reasonably straightforwards otherwise. In addition, links to specific draft standards can be found on cppreference [1].
But anyways, in the first C++20 post-publication draft (N4868), the wording you're interested in is in multiple sections. Section 22.2.3 Sequence Containers [sequence.reqmts] has Table 78: Optional sequence container operations [tab:container.seq.opt] (starting on page 815), which states that a precondition of pop_back() is that empty() returns false. Section 16.3.2.4 Detailed Specifications [structure.specifications] (page 481) states:
> Preconditions: the conditions that the function assumes to hold whenever it is called; violation of any preconditions results in undefined behavior.
Therefore, calling pop_back() on an empty vector results in undefined behavior.
> Is this something that in practice is implemented in different (exception-throwing) ways?
Based on a quick glance at the major implementations (libc++ 15.0.7 at [2], MSVC at [3], libstdc++ at [4]), it looks like asserts are used. Whether those result in exceptions probably depends on whether the asserts are compiled in in the first place and how they are implemented, but it's definitely not a guaranteed exception.
[0]: https://github.com/cplusplus/draft
[1]: https://en.cppreference.com/w/cpp/links
[2]: https://github.com/llvm/llvm-project/blob/llvmorg-15.0.7/lib...
[3]: https://github.com/llvm/llvm-project/blob/8dfdcc7b7bf66834a7...
[4]: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3...
this was something that I thought must be a joke at first... a text document that needs ... Perl ... to be read. This does make sense considering the context is C++ though.
For future reference, lots of other git-hosted projects also require the user to supply build tools to produce the finished product. Sometimes these are programs known as "compilers", but frequently other programs like "parser generators" or "text formatters" are needed too. Or scripting languages (like perl) to help tie the build process together.
Might be worth keeping in mind if you ever need to interact with git (or github) again.
Might be worth keeping in mind if you ever need to interact with git (or github) again.
Big mistake. I asked chatgpt to summarize the plot of 2001. It replied with Hal locked Dave inside the Discovery and wouldn't open the pod bay doors to let him out.
Answers about code is similarly very plausible, but subtly and completely wrong.
> When you call pop_back() on an empty vector in C++, it leads to undefined behavior. The C++ standard does not specify what should happen in this scenario. Attempting to remove an element from an empty container is an error and can cause the program to crash or produce incorrect results. To avoid this issue, you should always check the size of the vector before calling pop_back() or use other methods such as empty() to determine if the vector is empty.
Do you remember how you phrased your question? Maybe it's just luck it got it right for me or maybe it's the order of the terms in my question.
In C++, what happens when you call pop_back() on an empty vector?
When you call pop_back() on an empty vector in C++, an std::out_of_range exception is thrown. The pop_back() function removes the last element of a vector and it is undefined behavior to call it on an empty vector. Attempting to do so will result in the exception being thrown.
So it basically claims both that an exception is thrown, and that it's undefined behavior. At least in this case, one would know something is up.> In C++, calling pop_back() on an empty vector results in an undefined behavior. An std::vector is a dynamic array that grows and shrinks automatically. pop_back() function is used to remove the last element of the vector. But if there are no elements in the vector, calling pop_back() will result in an error. Therefore, it is advisable to always check if the vector is empty before calling pop_back().
I wonder what sort of scores we would be seeing for each of these series of tokens (including those returned for roel_v). Is the aggregate score (for lack of a better term) higher for the initial reply I saw greater than the scores for these other replies?
what happens when you do pop_back() on an empty vector in C++?
In C++, when you call the pop_back() function on an empty vector, it will result in an std::out_of_range exception being thrown. The exception indicates that an element cannot be removed from an empty vector, as there is nothing to remove. To prevent the exception, it is recommended to check the size of the vector before calling pop_back(), to ensure that the vector is not empty.
can you quote the relevant C++ standard on that?
Sure! Here is the relevant excerpt from the C++ Standard (C++20, ISO/IEC 14882:2020):
quote the relevant passage from the standard
Here is the relevant excerpt from the C++ Standard (C++20, ISO/IEC 14882:2020):
23.6.11 Vector data members [vector.data]
-1- The member function pop_back() shall have no effect if the vector is empty.
23.6.6 Vector capacity [vector.capacity]
-1- void pop_back();
Requires: empty() == false.
Effects: If size() > 0, caller shall call erase(end() - 1).
Throws: Nothing unless erase() throws an exception.
21.5.5.5 vector<T>::pop_back() [vector.pop_back]
-1- Removes the last element in the vector.
Complexity: Constant time.
Throws: Nothing unless erase() throws an exception.It gets the ISO/IEC number correct [1]. However, the sections are wrong
- Section 23.6 is about stream iterators. Sections 23.6.6 and 23.6.11 do not exist.
- Section 21.5.5 is a synopsis of the <cuchar> header. Section 21.5.5.5 does not exist
- Section [vector.data] exists and is numbered 22.3.11.4. It only describes the data() function.
- Section [vector.capacity] exists and is numbered 22.3.11.3. It describes the capacity(), reserve(), shrink_to_fit(), swap(), and resize() functions.
- pop_back() is generally described in Table 78 (Section 22.2.3 Sequence Containers, [sequence.reqmts]), and is expanded upon for std::vector in Section 22.3.11.5 Modifiers [vector.modifiers].
The wording is not correct either.
- Searching "shall have no effect" returns no hits (though I'm searching in a PDF, so maybe the search just misses it?).
- The standard wording for pop_back() in general is: "Effects: Destroys the last element. Preconditions: a.empty() is false". The Standard says nothing about exceptions.
- For std::vector specifically, the Standard says "Effects: Invalidates iterators and references at or after the point of the erase. Throws: Nothing unless an exception is thrown by the assignment operator or move assignment operator of T. Complexity: The destructor of T is called the number of times equal to the number of the elements erased, but the assignment operator of T is called the number of time equal to the number of elements in the vector after the erased elements."
[0]: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n48...
I don't think so. Even when enabling debugging mode, a precondition failure would cause an abort, not an exception to be thrown.