Why the exception is thrown on std::deque.erase()? - c++

This throws when trying to remove element from deque via iterator. The error is "can not seek value-initialized iterator" using VS2017. I wonder why this is happening, isn't std::deque a doubly linked list that does not invalidate iterators on push_front() / push_back()?
class deque2 {
public:
bool enqueue(int val) {
if (mp.find(val) != mp.end()) {
return false;
}
dq.push_front(val);
mp[val] = dq.begin();
return true;
}
int dequeue() {
if (dq.size() == 0) {
return -1;
}
int res = dq.back();
mp.erase(res);
dq.pop_back();
return res;
}
void erase(int val) {
auto it = mp.find(val);
if (it != mp.end()) {
dq.erase(it->second); // exception
mp.erase(val);
}
}
private:
deque<int> dq;
unordered_map<int, deque<int>::iterator> mp;
};

isn't std::deque a doubly linked list
No it is not. As stated in documentation
std::deque (double-ended queue) is an indexed sequence container that allows fast insertion and deletion at both its beginning and its end. In addition, insertion and deletion at either end of a deque never invalidates pointers or references to the rest of the elements.
emphasis is mine. Note that it says that pointer or references not invalidated, not iterators. And documentations on std::deque::push_front() clearly says so:
All iterators, including the past-the-end iterator, are invalidated. No references are invalidated.
As for the logic you are trying to implement I would recommend to use boost::multi_index as it allows single container with different access criteria and you do not have to maintain 2 containers in sync. Documentation can be found here

Related

Circular iteration of std::list

In my application I need the ability to traverse a doubly linked list starting from any arbitrary member of the list and continuing past the end(), wrapping around to the begin() and continue until the traversal reaches where it started.
I decided to use std::list for the underlying data structure and wrote a circulate routine to achieve this. However it's showing certain unexpected behavior when it's wrapping around from end() to begin(). Here's my implementation
template <class Container, class BiDirIterator>
void circulate(Container container, BiDirIterator cursor,
std::function<void(BiDirIterator current)> processor)
{
BiDirIterator start = cursor;
do {
processor(cursor);
cursor++;
if (cursor == container.end()) {
cursor = container.begin(); // [A]
}
} while (cursor != start);
}
// ...
typedef int T;
typedef std::list<T> TList;
typedef TList::iterator TIter;
int count = 0;
TList l;
l.push_back(42);
circulate<TList, TIter>(
l, l.begin(),
[&](TIter cur) {
std::cout << *cur << std::endl;
count++;
}
);
The output is:
42
-842150451
When I step through the code I see that the line marked [A] is never reached. The cursor is never equal to container.end(). Surprisingly, invoking ++ on that cursor, takes it to container.begin() in next pass automatically. (I suppose that's specific to this STL implementation).
How can I fix this behavior?
The issue here is that you are taking Container by value. This causes a copy so the iterators returned by container.end() and container.begin() are not that same as the iterator passed to the function. Instead if you pass Container by reference then the code works correctly.
Live Example

Obtain iterator upon adding to std::map?

Are there any methods of procuring an iterator, when working with a Standard Library map container, which don't require searching throughout the container?
I have a managing class for a map, and I wish to return the iterator associated to items added to the map. I don't want to rely upon find() if at all possible. If I can avoid searches I figure all the better.
std::map<char, bool>::iterator ClassA::Add(char item)
{
mymap[item] = false;
return mymap.get_iterator_lastitem();
}
Perhaps
return mymap.end() - 1;
If you're not using C++11, then
std::map<char, bool>::iterator ClassA::Add(char item)
{
std::pair<std::map<char, bool>::iterator, bool> result = mymap.insert(std::make_pair(item, false));
if(!result.second) {
// Item already exists, modify that existing item
result.first->second = false;
}
return result.first;
}
If you are using C++11 then it is better to use emplace + auto.
std::map<char, bool>::iterator ClassA::Add(char item)
{
auto result = mymap.emplace(item, false);
if(!result.second) {
// Item already exists, modify that existing item
result.first->second = false;
}
return result.first;
}
Live example
Both insert and emplace return a pair of an iterator and a boolean, of which the iterator points to the inserted or existing element and the boolean indicates whether an insertion (true) took place or if not (false) of which the returned iterator points to the already-existing element with the key.

Ordering output of C++ std::set

I want to list the output of my set in alphabetical order. Below is an attempt at getting to this, but it seems slow / inefficient and I haven't even finished it yet.
void ordered(ostream &os) {
bool inserted = false;
for (objects::iterator i = begin(); i != end(); ) {
for (objects::iterator x = begin(); x != end(); ++x) {
if((**i) < (**x)) { //overloaded and works
os << **i << endl;
inserted = true;
break;
}
}
if(inserted) {
++i;
}
}
}
Clearly this will only output objects that come after the first object alphabetically.
I also considered moving the objects from a set into another container but it still seems inefficient.
The std::set is an ordered container, see reference:
http://en.cppreference.com/w/cpp/container/set
std::set is an associative container that contains a sorted set of
unique objects of type Key. Sorting is done using the key comparison
function Compare. Search, removal, and insertion operations have
logarithmic complexity. Sets are usually implemented as red-black
trees.
std::set is already ordered. It looks like you merely need to use a custom comparer that compares the pointed-to values instead of the pointers themselves (which is the default):
template<typename T> struct pless {
inline bool operator()(const T* a, const T* b) const { return *a < *b; }
};
std::set<Foo*, pless<Foo> > objects;

Getting index of a std::vector<std::string>::iterator

So that's what I have tried so far:
class menu_item
{
private:
// ....
std::vector<std::string> options_;
std::vector<std::string>::iterator current_;
public:
menu_item(std::string name, std::vector<std::string> options)
: name_(name), options_(options)
{
current_ = begin(options_);
}
// ....
const int curr_opt_id()
{
return current_ - begin(options_);
}
};
But curr_opt_id() returns -24. Does anybody know what I am doing wrong here?
When you add to a vector, there's a chance that the internal storage will be reallocated which will invalidate all existing iterators. Doing arithmetic on an invalid iterator isn't going to end well.
See Iterator invalidation rules
Iterators of a vector get invalidated upon reallocation, which happens when the current capacity is not sufficient to hold the actual content plus a newly added element.
What is most likely happening here is that the current_ iterator, which is initialized at construction time, gets invalidated by subsequent insertions into options_, which gives you undefined behavior when evaluating the expression:
current_ - begin(options_)

generic "out of bounds", "past end" iterator

In my application I have a (unbalanced) tree datastructure. This tree is simply made of "std::list of std::lists" - node holds an arbitrary "list" of sub-nodes. Using this instead of a single list made the rest of the application a lot easier. (The program is about changing moving nodes from one tree to another tree / another part in the tree / to it's own tree).
Now an obvious task is to find a subtree inside a "tree". For non-recursive searches it is simple enough:
subtree_iterator find_subtree(const N& n) {
auto iter(subtrees.begin());
auto e(subtrees.end());
while (iter != e) {
if ((*iter)->name == n) {
return iter;
}
++iter;
}
return e;
}
Which returns an iterator to the subtree position. The problem however starts when I try to implement a multi-level search. Ie, I wish to search for hello.world.test where the dots mark a new level.
Searching worked alright
subtree_iterator find_subtree(const pTree_type& otree, std::string identify) const {
pTree_type tree(otree);
boost::char_separator<char> sep(".");
boost::tokenizer<boost::char_separator<char> > tokens(identify, sep);
auto token_iter(tokens.begin());
auto token_end(tokens.end());
subtree_iterator subtree_iter;
for (auto token_iter(tokens.begin()); token_iter != token_end; ++token_iter) {
std::string subtree_string(*token_iter);
subtree_iter = tree->find_subtree_if(subtree_string);
if (subtree_iter == tree->subtree_end()) {
return otree->subtree_end()
} else {
tree = *subtree_iter;
}
}
return subtree_iter;
}
On first glace it seemed to work "correct", however when I try to use it, it fails. Using it would be like
auto tIn(find_subtree(ProjectTree, "hello.world.test"));
if (tIn != ProjectTree->subtree_end()) {
//rest
}
however that gives a debug assertion error "list iterators not compatible". This isn't too weird: I'm comparing a iterators from different lists to each other. However I could I implement such a thing? My "backup" option would be to return a std::pair<bool,iterator> where the boolean part determines if the tree actually exists. Is there another method, short of making the whole tree single list?
You should not work on iterators internaly. Use nodes instead.
template <typename T>
struct Node {
T item;
Node<T>* next;
};
Then encapsulate your Node in an iterator facade like this :
template<typename T>
class iterator {
private:
Node<T>* node;
public:
...
};
Then use a generic invalid node (when node is nullptr) that is returned whenever end() is reached or returned.
Note that what i suggest is a single linked list (not double linked list as the standard one). this is because you can't go back from an invalid generic end() iterator that point to an invalid null node.
If you don't use iterator operator--() in your algorithms this should be fine.
std::vector<list_iterator> stack to traverse? Where the .back() of the stack is the only one allowed to be equal to end() of the previous one, and .front() is an iterator to the root list?