When looking over the member functions of the STL containers, an odd thought occurred to me. Why don't functions like std::vector<T>::push_back(T)
not have an (optional) return value (iterator or even a reference to the appended object)? I know std::string
functions like insert
and erase
return iterators, but that's for obvious reasons. I'd think it'd often save a second line of code that often follows these function calls.
I'm sure the designers of C++ have a very good reason, please enlighten me :)
UPDATE: I'm including a real-world code example here where it could reduce code length:
if( m_token != "{" )
{
m_targets.push_back( unique_ptr<Target>(new Dough(m_token)) );
return new InnerState( *(m_targets.back()), this );
}
could be reduced to
if( m_token != "{" )
return new InnerState( *(m_targets.push_back( unique_ptr<Target>(new Dough(m_token)) )), this );
If I assume std::list::push_back
returns a reference to the added element. The code is a bit heavy, but that's mostly (two sets of parentheses) due to unique_ptr
's constructor and dereferencing it. Perhaps for clarity a version without any pointers:
if( m_token != "{" )
{
m_targets.push_back( Dough(m_token) );
return new InnerState( m_targets.back(), this );
}
vs.
if( m_token != "{" )
return new InnerState( m_targets.push_back( Dough(m_token) ), this );
@BjörnPollex Yes! I forgot to mention that.
Functions. The STL includes classes that overload the function call operator. Instances of such classes are called function objects or functors. Functors allow the working of the associated function to be customized with the help of parameters to be passed.
Containers are the objects used to store multiple elements of the same type or different. Depending on that they can be further classified as − Sequence containers (array, vector, list) Associative containers (set, map, multimap)
The C++ STL (Standard Template Library) is a powerful set of C++ template classes to provide general-purpose classes and functions with templates that implement many popular and commonly used algorithms and data structures like vectors, lists, queues, and stacks.
Returning the added element, or the container in container member functions is not possible in a safe way. STL containers mostly provide the "strong guarantee". Returning the manipulated element or the container would make it impossible to provide the strong guarantee (it would only provide the "basic guarantee"). The reason behind this is, that returning something could possibly invoke an copy-constructor, which may throw an exception. But the function already exited, so it fulfilled its main task successfully, but still threw an exception, which is a violation of the strong guarantee. You maybe think: "Well then lets return by reference!", while this sounds like a good solution, its not perfectly safe either. Consider following example:
MyClass bar = myvector.push_back(functionReturningMyClass()); // imagine push_back returns MyClass&
Still, if the copy-assignment operator throws, we dont know if push_back succeded or not, thus indirectly violating the strong-guarantee. Even though this is not a direct violation. Of course using MyClass& bar = //...
instead would fix this issue, but it would be quite inconvenient, that a container might get into an indeterminate state, just because someone forgot a &
.
A quite similar reasoning is behind the fact that std::stack::pop()
does not return the popped value. Instead top()
returns the topmost value in a safe way. after calling top, even when a copy-constructor, or a copy-assignment constructor throws, you still know that the stack is unchanged.
EDIT: I believe returning an iterator for the newly added element should be perfectly safe, if the copy-constructor of the iterator-type provides the no-throw guarantee (and every i know of does).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With