Why doesn't pop_back()
have a return value? I have Googled regarding this and found out that it makes it more efficient. Is this the only reason for making it so in the standard?
I think there is something related to the fact that copying an instance of the last object could throw an exception. When doing so, you're losing your object, since pop_back() did remove it from your container. Better with a few lines of code:
std::vector<AnyClass> holds = {...} ;
try {
const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{
// Last value lost here.
}
pop_back
with no return value. –
Cullan noexcept
either, if I'm not mistaken –
Satang Efficiency has little (or nothing, really) to do with it.
This design is the outcome of an important paper by Tom Cargill, published in the 90s, that raised quite a few eyebrows back then. IIRC, in it Cargill showed that it is impossible to design an exception safe stack pop function.
pop_back
doesn't throw unless user is stupid? –
Marcusmarcy NULL
. –
Inge I think there is something related to the fact that copying an instance of the last object could throw an exception. When doing so, you're losing your object, since pop_back() did remove it from your container. Better with a few lines of code:
std::vector<AnyClass> holds = {...} ;
try {
const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{
// Last value lost here.
}
T container<T>::pop()
cannot be implemented exception safe (gotw.ca/gotw/008.htm) –
Misshapen pop_back
with no return value. –
Cullan noexcept
either, if I'm not mistaken –
Satang It's because of the Command-query separation principle.
Efficiency is one thing. Another reason for pop_back()
not returning an element is exception safety.
If the pop()
function returned the value, and an exception is thrown by the copy constructor, you may not be able to guarantee that the container is in the same state as it was before calling pop()
.
You can find more infos in Herb Sutters books about exceptions. I think this topic is covered here. But I am not sure.
The reason is not so much efficiency as exception safety. The container class can be used to store any kind of objects. It would be impossible to implement pop_back() in an exception safe manner if the function would return the object after deleting it from the container, because returning the value of the object involves copy construction.
This is the actual implementation of vector::pop_back() in GNU C++ standard library:
void
pop_back()
{
--this->_M_impl._M_finish;
this->_M_impl.destroy(this->_M_impl._M_finish);
}
This is what it would look like should it return the last element in the end:
value_type
pop_back()
{
value_type save = back();
--this->_M_impl._M_finish;
this->_M_impl.destroy(this->_M_impl._M_finish);
return save;
}
This involves two copy constructions, at the save = back()
statement and when returning a copy of the object. There are no guarantees that the return expression won't throw an exception after the element has been destroyed from the container.
Well, how many reasons there have to be?
This avoids potentially expensive copying of the object when you just want to remove it from the container. C++ has the philosophy of not paying for what you don't need.
It just pops, and if we want to know what was on the top of the stack before pop, we must look. This happens not to be my favorite style of stack, but it's arguably more efficient and it's the standard
. OTOH, Josuttis book also refers to Cargill paper. My conclusion is that performance is one of the reasons, while I don't claim that it is the only one. However, upon reading all the references I would also agree that exception-safety might have been more important factor in deciding this way. –
Obstructionist In computer programming, orthogonality means that operations change just one thing without affecting others.
pop_back()
does just one thing, it does not copy, hence it is orthogonal.
Why would it return the value? You can always access the value at any time prior to popping it off- there is no need for pop_back
to provide this functionality.
pop_back
doesn't return value, and this post doesn't talk about that rationale. –
Cullan pop_back()
returning a value. Traditionally, that's what a stack's pop function does. No, the reason is purely for exception safety. –
Inge © 2022 - 2024 — McMap. All rights reserved.
T container<T>::pop()
cannot be implemented exception safe (gotw.ca/gotw/008.htm) – Misshapen