multimap::erase() standard behaviour? - c++

I've been comparing documentation for the multimap::erase function. After checking out Josuttis and cplusplus.com, it looks as though there are three overloads:
void erase(iterator position);
size_type erase(const key_type& x);
void erase(iterator first, iterator last);
However, the MSDN documentaion appears to suggest three slightly different overloads:
iterator erase(iterator where);
iterator erase(iterator first, iterator last);
bool erase(key_type key)
Why the differences? Am I just being a bit slow and looking at the wrong docs, or has the standard moved on and I'm just looking at outdated documentation?

The correct overloads are (from http://en.cppreference.com/w/cpp/container/multimap/erase):
void erase( iterator position ); (until C++11)
iterator erase( const_iterator position ); (since C++11)
void erase( iterator first, iterator last ); (until C++11)
iterator erase( const_iterator first, const_iterator last ); (since C++11)
size_type erase( const key_type& key );
The cplusplus.com documentation is out of date; the Microsoft documentation is simply incorrect (overloads possibly copied erroneously from map documentation); it does say later that the third form returns a count of the number of elements removed so clearly cannot return bool.

According to this, it actually depends on the version of the standard your STL is conforming to.
What you read on MSDN is C++ 11, and on cplusplus.com it's for older C++.

The link from MSDN appears to document a library that wraps the STL for use in CLR. The first code snippet is correct and is the same as that in C++03 standard, and only differs from the C++11 standard in the iterators are const. From section 23.4.5.1 Class template multimap overview of the C++11 standard:
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);

The MSDN documentation you linked to is the STL/CLR version. That's a subset of the Standard C++ Library for use with C++ and the .NET Framework common language runtime (CLR).
The correct MSDN C++ documentation for std::multimap::erase is here.

Related

New std::map::erase() signature C++17

According to this answer, an iterator must be implicitly convertible to const_iterator. Since that is true, as we can see happening in insert_or_assign(), then why in C++17 was a new signature added to std::map::erase()?
In C++11, we have iterator erase( const_iterator pos );
In C++17, we now have iterator erase( iterator pos );
Wasn't the C++11 signature good enough to receive iterator and const_iterator?
There's a potential ambiguity with erase(const key_type& key) when you pass an iterator. Consider the case where the key_type is something like std::any.

Classification of std::vector's iterators

In the description of std::vector on cppreference (http://en.cppreference.com/w/cpp/container/vector/begin), I miss the categorization of the iterator (according to http://www.cplusplus.com/reference/iterator/) that is returned by the begin() function (the same applies for the iterator returned by end()).
Does cppreference not have to state which category of iterator is returned by begin() so that the user knows the iterator's functionality?
Currently, for me, it remains unclear which functionality std::vector's iterators provide.
Look at the main desciption of std::vector under the section Member types:
iterator RandomAccessIterator
const_iterator Constant random access iterator
reverse_iterator std::reverse_iterator<iterator>
const_reverse_iterator std::reverse_iterator<const_iterator>
std::vector uses RandomAccessIterator
A RandomAccessIterator is a BidirectionalIterator that can be moved to
point to any element in constant time. A pointer to an element of an
array satisfies all requirements of RandomAccessIterator
...
On the cppreference page for std::vector you will find:
Member types
============
...
iterator RandomAccessIterator
From here http://en.cppreference.com/w/cpp/container/vector you can see that a vector's iterators model the RandomAccessIterator concept: http://en.cppreference.com/w/cpp/concept/RandomAccessIterator
std::vector::begin() returns a std::vector::iterator (or const_iterator)
std::begin(x) returns the result of x.begin()
Therefore std::begin(std::vector<...>) will return a random access iterator.

Why const_iterator could be used with std::map::erase

I was under the impression one cant use erase on a const iterator. Check this code.
Why does the below code compile (C++11, gcc)?
long getMax(const bool get_new)
{
long max_val=0;
TO now=getNow();
map<TO, long>& m=get_new?m_new:m_old;
for(auto it=m.cbegin(); it !=m.cend())
{
if(now.compareTime((*it).first)<lookback)
{
max_val=max(max_val,
(*it).second);
++it;
}
else
{
it=m.erase(it);
}
}
return max_val;
}
The map itself is not constant, but my understanding is that the const iterator should make this fail.
The behavior has changed from C++11; std::map::erase takes const_iterator as its parameter.
void erase( iterator pos ); // (until C++11)
iterator erase( const_iterator pos ); // (since C++11)
iterator erase( iterator pos ); // (since C++17)
For std::map::erase, the passed iterator is just used as the position where the element would be deleted, not for modifying the element through it. That means const_iterator would be fine. Before C++11, the support for const_iterator was not very good, but the situation has changed from C++11. You should use const_iterator instead of iterator when possible now.
Positions are independent of the constness of their access. It was (is?) quite common that functions doing a search return const_iterator because they actually do not change the container at all. However, it is desirable to use the obtained position for mutations of the sequences, e.g., to insert() an element at the corresponding position or to erase() the located element. As a result, the container where extended to support use of const_iterator with mutating operations.
It seems the relevant paper is N2350. I'm not sure if this paper is the latest version.

What is the difference between SGI slist and C++11 forward_list?

Both SGI slist and C++11 std::forward_list appear identical to me unless I have missed something; both implement a singly-linked list.
I assume there is a difference though as the C++ Standard Commitee didn't adopt the name slist and instead chose a new name, forward_list, when they added the container into the Standard Library for C++0x.
One major difference is that std::forward_list lacks a size() member function, where as the sgi::slist doesn't. The motivation for this is that an O(N) size() has been problematic. N2543 has more details on the design decisions for forward_list.
Update:
I recently had a good excuse to look closer at this subject. slist also has other member functions that one would be tempted to think are O(1), but are really O(N). These include:
iterator previous(iterator pos);
const_iterator previous(const_iterator pos) const;
iterator insert(iterator pos, const value_type& x);
iterator erase(iterator pos);
void splice(iterator position, slist& x);
void splice(iterator position, slist& x, iterator i);
In short, if you're not very careful, you can end up with significant performance problems by using slist. Use of std::forward_list instead ensures that you'll get the expected O(1) performance out of your singly linked list.
So put simply, sgi::slist and forward_list are very similar.
The differences being that forward_list lacks a size() member function which is included in sgi::slist and forward_list includes an emplace_after member function which isn't included in sgi::slist. Also, forward_list doesn't provide insert and erase member functions like sgi::slist does.
If you know of any other differences, please don't hesitate to mention them.
I've recently run into another difference. The method splice_after has a different interface and different behaviour.
1) forward_list Requires you to pass the container you're moving from as a second argument:
void splice_after( const_iterator pos, forward_list& other,
const_iterator first, const_iterator last );
slist:
void splice_after(iterator pos, iterator before_first, iterator before_last)
This is similar for the overloads.
2) Specific for the overload mentioned above: the last iterator is interpreted differently! Where slist moves the range [ before_first + 1, before_last + 1 >, forward_list moves the range < first, last >. So, when converting code (since slist is deprecated in GCC, for instance), make sure to use: last = before_last + 1.

implementation of string class

I'm interested in the implementation of the reverse iterator with rbegin(), rend() and operator++ of the class string, I can't find it in google, how can I do it? thanks in advance for any help or any link
You could look in the implementation header files. (e.g. /usr/include/c++/4.1.2/string on Linux). This will typically just pull in a load of other headers where the real meat lies, such as bits/basic_string.h.
I don't know where they reside for e.g. VC++, but you can usually just get Intellisense to find it by creating a std::string, selecting it and pressing F12.
There is a basic implementation of reverse_iterator in the STL.
It is templatized by the Iterator to be reverted.
The idea is quite simple, if you look at a range:
[first, second, .... last]
^ ^
begin end
rend rbegin
There is extra-work done, compared to a pure reverse iterator using this implementation, since for each dereference, you need to copy the iterator you hold, decrement it, and then dereference it.
Reverse iteration for bidirectional iterators is implemented in the std::reverse_iterator template.
The implementation of reverse iterators for std::string doesn't take more than:
template <xxx>
class basic_string
{
public:
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
reverse_iterator rbegin() { return reverse_iterator(this->end()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(this->end()); }
reverse_iterator rend() { return reverse_iterator(this->begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(this->begin()); }
//...
};
(Copied from GCC's implementation.)