In his excellent book "C++ Concurrency in Action" (2nd edition including C++17) Anthony Williams discusses the implementation of a thread-safe stack.
In the course of this, he proposes an adapter implementation of std::stack, which, among other things, would combine the calls of top() and pop() into one. The separation into 2 separate functions, however, was done for a reason in std::stack, namely to avoid losing data in the case that a potential copy made when returning the popped element to the caller throws an exception inside the copy constructor. When returning, the element will have already been popped off and is consequentially lost.
Instead of having a function T pop(), he proposes other variations of pop that would be able to remove the element off the stack and provide it to the caller in one operation, all of which come with their own problems, though.
The 1st alternative he proposes has the signature void pop(T&). The caller passes in a reference to a T and gets the popped off object that way. This way of doing it, however, comes with the problem that a T need be constructed prior to the call to pop, which might be an expensive operation, or it might not be possible to construct a T beforehand at all because necessary data might not be available yet at the time. Another problem the author mentions is that T might not be assignable, which would be required for this solution, though.
Now my question: Wouldn't all of the mentioned problems be solved if we passed a std::optional<T>& instead of a T&?
In that case, no instance of T would need to be constructed prior to the call to pop. Furthermore, assignability would not be required anymore either, since the object to be returned could be constructed into the std::optional<T> instance directly using its emplace function.
Am I missing something crucial here or am I right? If I am indeed right, I would be curious to know why this was not considered (for a good reason or just plainly an oversight?).
std::optional does solve all of the mentioned problems, and using it to control lifetime can be quite valuable, although it would appear a bit strange in
std::optional<T> o;
st.pop(o);
to have o always engaged.
That said, with a stupid scope-guard trick it's possible in C++17 to safely return T even without requiring no-throw-movability:
T pop() {
struct pop_guard {
C &c;
int u=std::uncaught_exceptions();
~pop_guard() {if(std::uncaught_exceptions()==u) c.pop_back();}
} pg{c};
return std::move(c.back());
}
(We could of course test for a throwing move and just move (perhaps twice) in its absence.)
However, what wasn't mentioned is that separate top and pop allows a T that isn't even movable, so long as the underlying container supports it. std::stack<std::mutex> works (with emplace, not push!) because std::deque doesn't require movability.
Related
It could be implemented thusly:
std::shared_ptr<T> operator->() {
auto shared = lock();
if(shared == nullptr) {
throw std::bad_weak_ptr(); // or some other exception
}
return shared;
}
Live Demo
Why did the authors of weak_ptr decide to not have operator->? (They must have thought of it)
I can think of potential reasons but I wonder what the official reason is, if one exists. Potential reasons:
Discourage extra increment/decrement of reference count for multiple calls
Encourage explicit locking rather than (somewhat hidden) exceptions
If you are confused about the lifetime of the returned shared_ptr, see this paper.
Also, someone asked why would one use a weak_ptr if you expect it to not be expired? Answer: cycles.
The original proposal weak_ptr didn't include an overload of operator->.
I haven't looked through the minutes of every meeting since, but have followed what's been discussed, and don't recall a mention of anybody having proposed that it should be added. As such, the "official" reason it's not present is probably largely that nobody's proposed that it be added.
If you want to go back to the very beginning, most of this stems from John Ellis and David Detlef's Safe, Efficient Garbage Collection for C++ paper, from Usenix 1994. That included a weakptr type in its Appendix B. That's somewhat different (weakptr::pointer returns a pointer directly, or a null-pointer if the pointee has already been destroyed), but still didn't use an operator overload to do the job.
Greg Colvin wrote the original proposal to add counted_ptr to the standard. Its counted_ptr was essentially equivalent to what's now called shared_ptr, but did not include anything analogous to weak_ptr.
Shortly after the committee rejected the counted_ptr proposal and adopted auto_ptr instead, the basic idea of counted_ptr was revived on Boost. I don't remember seeing any discussion of adding an operator-> to it, but it "lived" there for so long that it's entirely possible somebody could have proposed it without my being aware of it.
I'll take a shot at giving a good reason why this is not a good idea:
One thing is clarity:
ptr->foo();
ptr->bar();
The problem here is that somewhere between the first and second call, ptr might expire, either by a different thread (which would be a race condition) or by a sideeffect of the call to foo.
Another thing is symmetry: When I have a pointer, I expect operators *, -> and an implicit conversion to a boolean value. Some might disagree, but operators * and -> often coincide. I'd be surprised that this isn't the case here.
That said, with C++11, it's just too easy to write:
if (auto p = ptr.lock()) {
p->foo();
p->bar();
}
Knowing that ptr is a weak_ptr, the meaning and behaviour of that code is pretty clear.
I come from Java, where filling containers did not involve thinking. My problem now that i work with c++ is, that filling a container in a function with data which is declared in function scope can lead to errors, where the data doesn't exist any more when I want to access it.
I could not find tutorials addressing the problem, so I went the Java way and only made containers getting pointers declared with "new". But now I am forced to return a
std::list<Vertex<float> >
from a function and thought this might be a good point to learn how I would fill and return such a thing. Would this
{
std::list<Vertex<float> > myList;
Vertex<float> v(0.0, 0.1, 0.2);
myList.push_back(v);
myList.push_back(Vertex<float>(1,0, 1.1, 1.2));
return myList;
}
actually be fine as a sample function body? And if yes, why would v still exist outside of the scope? Does each insertion in a container also imply a copying?
This would work "fine" since every operation there creates a copy.
myList.push_back(v); creates a copy of v so that visiblity of v is now irrelevant.
return myList; returns a copy of the list to the calling function so the visiblity of myList is now irrelevant. The calling function should make a copy of this list to keep it in scope, else it will be destroyed at the end of execution of the line that calls this function.
The reason that fine is quoted is that copies are typically expensive. In your case they are quite small so it might be irrelevant, and in many cases they might be optimised away, but it is still something to keep in mind.
Old C++ way of optimizing is to pass a list by reference and use that to construct your list, instead of returning by value.
void MakeMeAList(std::list<Vertex<float> >& aList){
....
}
std::list<Vertex<float> > aList;
MakeMeAList(aList);
As #billz suggests, Return Value Optimization should optimize away the copies even if this is not done.
New C++ (c++11) -
The use of emplace_back to construct the list, would be more efficient that copying, as long as the input variables are not going to be used any more. ( thanks #Troy)
My C++11 is weak, I am almost sure even returning by value is OK since Move semantics would optimize it away, but I am only 95% sure.
To add to Karthik's reply, if you're using a relatively new compiler that implements r-value references (part of C++0x standard), your approach will work perfectly without the negative impact of the copy operation.
Check out http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
for a brief intro to r-values.
Note that before r-value references were adopted, many compilers eliminated the 'expensive copy operation' involved in returning collections through what is called Return Value Optimization. Again Wiki has more details:
http://en.wikipedia.org/wiki/Return_value_optimization
Visual Studio 2005 (and newer) implements RVO, and I believe GCC also has a similar feature. So effectively, your code, which is more readable than using arguments to return values, is the correct approach and ought to work very well if you're using the latest compilers.
I know std::queue::pop() returns void. For two reasons:
exception safety: something might throw after removing the element
to be able to return the value by reference
Fine.
Now if I understand the new C++11 move semantics correctly, the second is no longer a valid argument.
So... the only thing preventing std::queue to have a pop-like function returning the value lies in the possibility that the move constructor throws?
I have a hard time thinking of situations where such a move constructor would throw. Who knows of an example?
I guess the same goes for std::stack::pop(), std::vector::pop_front(), std::vector::pop_back(), std::deque::pop_front(), std::deque::pop_back(), std::list::pop_front(), std::list::pop_back() and what not.
There aren't many cases where std::move() can throw in the standard library but there are cases. For example, if the container uses a stateful allocator, its children also use this allocator, but it won't be moved to a result: this would rather get a default constructed version of an allocator (if I remove correctly). Given that the allocators are stateful this means that the object can't be moved and thus the move construction fails with an exception. Why does this type then have a move constructor? Well, because it might be instantiated with non-stateful allocator in which case moving won't throw. In addition, once we move to user defined classes we have no idea under which condition moving them might throw.
Using clever SFINAE techniques it would indeed be possible to have an atomic non-throwing pop_and_move() for just datatypes that implement no-throwing move or no-throwing copy.
There is even a noexcept() construct available to see if something might throw.
One of the new concepts in C++11 in particular that extends SFINAE is that if the body doesn't compile the function doesn't exist. Thus one could implement based on noexcept().
I would say for backward compatibility the function would need a new name, which therefore allows it to co-exist with the existing functionality of calling them separately, not breaking containers of types that do not have the semantics to allow it.
Another problem is, that not every class really benefits from moving, i.e., they might only have a copy ctor.
struct DontLikeMoves{
// some data, whatever...
DontLikeMoves(DontLikeMoves const& other){
// might throw, who knows!
// and this will even get called for rvalues
}
};
std::vector<int> a;
a.push_back(1);
a.push_back(a[0]);
I just learned that the code above can be very dangerous.
(If it's not obvious why, you're not alone... it wasn't obvious to me either.)
My questions:
What is the "standard" way of dealing with it? Making a new variable and then assigning it immediately to something afterward seems a bit weird to me. Is there a better way of dealing with it?
How do you train yourself to watch out for aliasing issues like this? What pattern(s) do you look for? I have no idea to recognize this situation; I only learned about aliasing when I learned about the restrict keyword in C, and only now do I understand what the issue really is.
Edit:
I'd love to accept an answer, but it doesn't seem like part (2) of the question has been answered. I'm wondering what strategies people use to locate aliasing mistakes in code they have written.
One strategy I've come up with so far is to avoid passing in the same value for in two parameters. (In this case, one parameter is implicit and one explicit.)
Are there any other easy things to notice and watch out for?
EDIT: Technically, the standard does not mandate that this is correct if the contained type has a no-throw copy constructor. I don't know any implementation where this does not hold anyway, as it would require producing two implementations of push_back when the generic one is just as efficient in all cases.
Aliasing is a problem in general, but not in this particular case. The code:
assert( v.size() > 0 );
v.push_back( v[0] );
Is guaranteed to be correct by the standard (C++03) through the exception guarantees (which are a really good reason not to implement your own containers, you will probably not get them right). In particular §23.1 [lib.container.requirements] / 10 dictattes:
Unless otherwise specified (see 23.2.1.3 and 23.2.4.3) [NOTE: both those references refer to insert on deque and vector respectively] all container types defined in this clause meet the following additional requirements:
— if an exception is thrown by a push_back() or push_front() function, that function has no effects.
Where the important bit is that if any exception is thrown in the operation, the container is left untouched, and that means that no iterator gets invalidated, which in turns means that the original region of memory is left untouched until it is guaranteed that no exceptions will be thrown (with the exception pun intended, of destructors). Because in general copy constructors can throw, the implementation must ensure that all copies are performed before destroying any object.
This becomes more evident in C++0x, when objects are not copied from one location to another, but rather moved. Because the copy of the new element might throw, it has to be performed before any of the moves are executed, or else you would be left in a situation where some of the objects in the original container have been invalidated.
I guess this would be safe:
std::vector<int> a(1);
a.push_back(1);
a.push_back(int(a[0]));
In push_back(const T& el); implementation to check if el is inside array or other internal storage. That is the only politically correct way of dealing with such problems.
Container should handle this as different containers - different safety rules.
This probably isn't a useful answer for you, but IMHO the "right" way is that the container class should handle aliasing correctly, so that the caller doesn't have to worry about it. In particular, push_back() (or equivalent) should do the following:
// C++-ish pseudo-code, exception-safety left as an exercise for the reader
void push_back(const T & t)
{
if (current_size == alloced_size)
{
// Oops, our data array is full. Time to trade it in for a bigger one
T * newArray = new T[alloced_size*2];
copy_items(newArray, current_array, current_size);
newArray[current_size++] = t;
delete [] current_array; // delete old array only AFTER all references to t
current_array = new_array;
alloced_size *= 2;
}
else current_array[current_size++] = t;
}
I'm just winging this, so please don't consider it gospel, but would this work?
a.push_back(1);
a.push_back(&(new int(a[0])));
Why does std::stack::pop() not throw an exception if the stack is empty and there is nothing to pop?
(I'm designing a specialized Stack for my own code and would like to know the tradeoffs with this approach (which requires one to manually check if the stack is empty) vs. throwing an exception.
My guess here would be that although C++ supports exception-handling, it comes with a small runtime overhead, and therefore, for maximum performance, the decision was made not to throw an exception in std::stack::pop).
I would argue that the reason pop() doesn't have to throw an exception has nothing to do with efficiency or performance, but with - exceptions.
As is argued elsewhere:
SGI explanation: http://www.sgi.com/tech/stl/stack.html
One might wonder why pop() returns
void, instead of value_type. That is,
why must one use top() and pop() to
examine and remove the top element,
instead of combining the two in a
single member function? In fact, there
is a good reason for this design. If
pop() returned the top element, it
would have to return by value rather
than by reference: return by reference
would create a dangling pointer.
Return by value, however, is
inefficient: it involves at least one
redundant copy constructor call. Since
it is impossible for pop() to return a
value in such a way as to be both
efficient and correct, it is more
sensible for it to return no value at
all and to require clients to use
top() to inspect the value at the top
of the stack.
std::stack < T > is a template. If pop() returned the top element, it
would have to return by value rather
than by reference as per the of above
explanation. That means, at the caller
side it must be copied in an another T
type of object. That involves a copy
constructor or copy assignment
operator call. What if this type T is
sophisticated enough and it throws an
exception during copy construction or
copy assignment? In that case, the
rvalue, i.e. the stack top (returned
by value) is simply lost and there is
no other way to retrieve it from the
stack as the stack's pop operation is
successfully completed!
Once we conclude that pop should not return the element it pops and thus its interface is fixed as void pop(), it - this being my opinion - doesn't make any sense anymore to prescribe what happens when pop() is called on an empty stack.
Note that the standard requires !empty()as precondition for calling pop().
UncleBens (in the comments) certainly has a point that not checking preconditions at runtime (which is never prescribed by the C++ std AFAIK) has a certain performance smell to it. However, to quote part of the original question: (emphasis mine)
(I'm designing a specialized Stack for
my own code and would like to know the
tradeoffs with this approach (which
requires one to manually check if the
stack is empty) vs. throwing an
exception.
I will argue, that the fact that pop() doesn't return anything renders the question moot. It (IMHO) simply doesn't make sense to force pop() to validate if the stack is empty, when we really don't get anything back from it (i.e. if the stack would be empty pop() can simply be a noop, which is (admittedly) not prescribed by the Std either).
I think one can either ask why top() does not throw an exception or one can ask why pop() doesn't return the top element. If pop doesn't return anything, throwing an exception doesn't make sense (in the C++ world) -- Claiming that it doesn't throw an exception "because of the runtime costs of exceptions" like other answers seem to imply is - IMHO - missing the point.
You are correct. The C++ standard always prefers performance to safety. But there may be STL implementations that include debug range checks.
As almost all features in C++, they are designed around the concept that you don't pay for what you don't use. Not all environments support exceptions, traditionally, and most notably game development.
So forcing the use of exceptions if you use std::stack would be failing one of the design guidelines. You want to be able to use stack even if exceptions are disabled.
I think it's worth mentioning that pop() is allowed to throw if the stack is empty -- it's just not required to. In your stack, you could assert that the stack wasn't empty, and that would be perfectly fine (pop on an empty stack seems to give UB, so you can do pretty much whatever you want, really).
exceptions are optional, and the STL wants to be available everywhere. think embedded systems: lots of C++ code, no exception support from runtimes.
Performance aside, I don't think popping from an empty stack is an exceptional scenario - therefore I would't throw there either.