Error Window pops up right away, the program crashes etc.
Code:
void sort_star(vector<string>& product, vector<double>& star_rating)
{
vector<string>::iterator piter;
vector<double>::iterator cycler;
piter = product.begin();
cycler = star_rating.begin();
while (piter != product.end() && cycler != star_rating.end())
{
++piter; ++cycler;
cout << "/n|" << *piter << "|";
cout << *cycler << " Stars";
}
}
Yea so I'm pretty new and don't know too much on C++. A good explanation would be much appreciated!
In your while loop you increment your iterators BEFORE using them
...
while (piter != product.end() && cycler != star_rating.end()) {
++piter; ++cycler; <--- HERE
This means two things:
you skip the first element
your iterator reaches end() which is a pointer to the PAST-END-POSITION and not a valid element see here.
FIX Increment at end of loop like so:
while (piter != product.end() && cycler != star_rating.end()) {
cout << "/n|" << *piter << "|";
cout << *cycler << " Stars";
++piter; ++cycler;
}
You are dereferencing iterators after incrementing. This will
skip the first elements to be printed
will try to dereference the std::vector::end iterator.
Obviously
std::vector::end:
Returns an iterator to the element following the last element of
the container. This element acts as a placeholder; attempting to
access it results in undefined behavior.
You could have done it in a for loop as follows:
for ( ; piter != product.end() && cycler != star_rating.end(); ++piter, ++cycler)
{ // ^^ ^^^^^^^^^^^^^^^^^^
cout << "/n|" << *piter << "|" << *cycler << " Stars";
}
Related
I do not know, why does it output 1024?
vector<int> default_container = { 1,2,3,4,5,6,7,78,8,1024 };
cout << *default_container.end() << endl; // 0
default_container.pop_back();
for (auto it : default_container)
{
cout << it << ",";
}
cout << endl;
cout << *default_container.end() << endl; // 1024 why?why?why?why?
cout << *--default_container.end() << endl; // 8
Your program has Undefined behavior!
You are de-referencing the end iterator, at the lines
cout << *default_container.end() << endl;
...
cout << *default_container.end() << endl;
which gives you undefined behavior. Form cppreference.com the std::vector::end, std::vector::cend
Returns an iterator to the element following the last element of the vector.
This element acts as a placeholder; attempting to access it results in undefined behavior.
Means, anything can be happened; therefore you shouldn't be relaying on its result and should not be doing it!
That being said, it looks like that you want to access the last element in the vector. If that the case, for a non-empty vector you have multiple other (safe) choices:
Using std::vector::back
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << default_container.back();
Using std::prev
#include <iterator>
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << *std::prev(default_container.end());
Using reverse iterator std::rbegin
// prints first 8 from last; due to "default_container.pop_back()"
std::cout << *std::rbegin(default_container);
As a side note, see: Why is "using namespace std;" considered bad practice?
The previous answer says it all.
In other words you're not supposed to use end() for anything else then comparing an iterator to.
Eg.
for (auto it = container.begin(); it < container.end(); ++it)
Also note that your line for (auto it : default_container)
isn't creating an iterator but literally an int.
// foreach value in container
for(int value : default_container)
{
cout << value;
}
note that if you're not planning to change the values you're iterating over you can use this :
for(const auto value : default_container) {}
or if your containter contains objects (instance of classes)
for(const auto& object : container) {}
I am trying to remove elements in a list when a condition is met in a std::list. What I have read in the Reference about the return value of the erase function:
An iterator pointing to the element that followed the last element
erased by the function call. This is the container end if the
operation erased the last element in the sequence.
Member type iterator is a bidirectional iterator type that points to
elements.
I have put this example together:
#include <string>
#include <list>
#include <iostream>
int main()
{
typedef std::list<std::string> string_list_t;
string_list_t list;
list.push_back("test1");
list.push_back("test2");
list.push_back("test3");
list.push_back("test4");
list.push_back("test5");
list.push_back("test6");
list.push_back("test7");
list.push_back("test8");
for (string_list_t::iterator it = list.begin(); it != list.end(); ++it)
{
std::string &str = *it;
std::cout << "Checking " << str << "..." << std::endl;
if (str == "test4")
{
std::cout << "Found test4!" << std::endl;
}
else
{
it = list.erase(it);
}
}
return 0;
}
It does not give me the expected output, instead it gives me:
Checking test1...
Checking test3...
Checking test5...
Checking test7...
Can someone help me figuring out what I understood wrong? Somehow it skips every second element...
You are skipping the element after the deleted one.
You should use either it = list.erase(it); or ++it, but not both.
When you erase an element from a std::list, do not increment the iterator returned by the std::list::erase method. You will not just skip the next element, you may just end up incrementing an end() iterator.
Change your loop to:
for (string_list_t::iterator it = list.begin(); it != list.end(); )
//^^ Not incremented
{
std::string &str = *it;
std::cout << "Checking " << str << "..." << std::endl;
if (str == "test4")
{
std::cout << "Found test4!" << std::endl;
++it; //increment
}
else
{
it = list.erase(it);
}
}
See it Live Here
I have tried many other similar questions but none of them helped me. My problem is as following:
I have 3 vectors of pointers to my struct: vector<state*>where state is my kind of struct. What I am trying to do is to remove states from vectorCheck if they are in either vectorOpen or vectorClosed. The point is, it sometimes works fine and sometimes not. According to CodeBlocks this seems to be a problem but I have no idea to overcome this. I debugged my program step by step and at some point, state from vectorCheck is not being removed despite of the fact it is in vectorClosed.
Iterating is held by 2 for loops:
vector<state*> vectorOpen;
vector<state*>::iterator itOpen;
vector<state*> vectorClosed;
vector<state*>::iterator itClosed;
vector<state*> vectorCheck;
vector<state*>::iterator itCheck;
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
if ((*itCheck)->player->x == (*itOpen)->player->x &&
(*itCheck)->player->y == (*itOpen)->player->y &&
(*itCheck)->box[0].x == (*itOpen)->box[0].x &&
(*itCheck)->box[0].y == (*itOpen)->box[0].y) {
cout << "erasing as in open " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
vectorCheck.erase(itCheck);
}
}
}
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
for(itClosed = vectorClosed.begin(); itClosed != vectorClosed.end(); itClosed++) {
if((*itCheck)->player->x == (*itClosed)->player->x &&
(*itCheck)->player->y == (*itClosed)->player->y &&
(*itCheck)->box[0].x == (*itClosed)->box[0].x &&
(*itCheck)->box[0].y == (*itClosed)->box[0].y) {
cout << "erasing as in closed " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
vectorCheck.erase(itCheck);
}
}
}
Where vectorCheck is a maximum size of 3. To explain what I mean here is the picture
Where I am talking here about states in green rectangulars (3 1 2 4). Why isn't it being removed like the state in blue rectangular (2 2 2 4)? It should be removed as this state has appeared already in vectorClosed (code above).
What am I doing wrong? This is not the first iteration of the program, it happens in like 6th or 7th loop.
Also, this is probably causing my program to crash later on.
As mentioned in my comment, the problem is that you are continuing to use an iterator to an element you erased. std::vector::erase(i) is invalidating the itCheck iterator.
We can fix this by taking advantage of C++ algorithms like std::remove_if. It may make the code appear more complex at first glance, but you'll find this style of coding lets you reuse pieces of logic, improving the readability and maintainability of your code.
To start, let's write a functor that does the equality comparison you need.
struct states_are_equal :
public std::binary_function<state const *, state const *, bool>
{
bool operator()(state const * a, state const * b) const {
return a->player->x == b->player->x &&
a->player->y == b->player->y &&
a->box[0].x == b->box[0].x &&
a->box[0].y == b->box[0].y;
}
};
Now we need a predicate that will return true if the given item is found within another container. This part admittedly may be a bit hard to follow if you are not familiar with the algorithms library.
template <typename Iterator, typename Comparer>
struct is_in_container_func :
public std::unary_function<
typename std::iterator_traits<Iterator>::value_type const &,
bool
>
{
is_in_container_func(Iterator begin, Iterator end, Comparer cmp)
: it_begin(begin), it_end(end), comparer(cmp) { }
bool operator()(argument_type i) const {
return std::find_if(it_begin, it_end, std::bind1st(comparer, i)) != it_end;
}
private:
Iterator it_begin;
Iterator it_end;
Comparer comparer;
};
// This is just a helper to allow template type deduction; its only purpose is to
// allow us to omit the types for Iterator and Comparer when constructing an
// is_in_container_func object.
template <typename Iterator, typename Comparer>
is_in_container_func<Iterator, Comparer> is_in_container(
Iterator begin, Iterator end, Comparer cmp)
{
return is_in_container_func<Iterator, Comparer>(begin, end, cmp);
}
Now we can put all of these pieces together with std::remove_if:
std::vector<state*> vectorOpen;
std::vector<state*> vectorClosed;
std::vector<state*> vectorCheck;
// Make one pass, removing elements if they are found in vectorOpen.
std::vector<state*>::iterator new_end = std::remove_if(
vectorCheck.begin(), vectorCheck.end(),
is_in_container(vectorOpen.begin(), vectorOpen.end(), states_are_equal()));
// Make another pass, removing elements if they are found in vectorClosed.
new_end = std::remove_if(
vectorCheck.begin(), new_end,
is_in_container(vectorClosed.begin(), vectorClosed.end(), states_are_equal()));
// std::remove_if just swaps elements around so that the elements to be removed are
// all together at the end of the vector, and new_end is an iterator to the first
// one. So, finally, we just need to remove the range [new_end, end()).
vectorCheck.erase(new_end, vectorCheck.end());
The erase call invalidates the iterator passed to it. It shifts the elements in the vector one place to their left, and returns an iterator to the element after the removed one. Therefore, you should not increment the iterator if the erase was executed. Like so:
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end();) { // no increment
bool found = false;
for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
if ((*itCheck)->player->x == (*itOpen)->player->x &&
(*itCheck)->player->y == (*itOpen)->player->y &&
(*itCheck)->box[0].x == (*itOpen)->box[0].x &&
(*itCheck)->box[0].y == (*itOpen)->box[0].y) {
cout << "erasing as in open " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
itCheck = vectorCheck.erase(itCheck);
found = true;
break; // found element and erased it. back to outer loop
}
}
if (!found) ++itCheck; // didn't find it, need to increment
}
I have a std::set of strings and I want to iterate over them, but the iterator is behaving differently for different sizes of set. Given below is the code snippet that I'm working on:
int test(set<string> &KeywordsDictionary){
int keyword_len = 0;
string word;
set<string>::iterator iter;
cout << "total words in the database : " << KeywordsDictionary.size() << endl;
for(iter=KeywordsDictionary.begin();iter != KeywordsDictionary.end();iter++) {
cout << *iter;
word = *iter;
keyword_len = word.size();
if(keyword_len>0)
Dosomething();
else
cout << "Length of keyword is <= 0" << endl;
}
cout << "exiting test program" << endl;
}
The code is working properly & *iter is being dereferenced & assigned to word until the size of KeywordsDictionary is around 15000. However when the size of KeywordsDictionary increases beyond 15000,
the print statement cout << *iter; is printing all the contents of KeywordsDictionary correctly.
but the pointer to the iterator *iter is not being dereferenced & not being assigned to word. word is just being an empty string.
EDIT: And the output of the program is :
total words in the database : 22771
�z���AAAADAAIIABABBABLEABNABOUTACACCEPTEDACCESSACCOUNT...
Length of keyword is <= 0
exiting test program
So basically, I'm guessing the loop is executing only once.
Try to declare keyword_len as
std::string::size_type keyword_len = 0;
instead of
int keyword_len = 0;
I have my std::map defined as
typedef std::map<string,ImageData*> ImageDataMap;
typedef std::pair<string,ImageData*> ImageDataPair;
typedef std::map<string,ImageData*>::iterator ImageDataIterator;
The above map stores string which is an image file name and ImageData which is the the image metadata. When i use the find as shown below
ImageDataIterator iter = imageMap->find("Fader.tga");
if(iter == imageMap->end()){...}
The iter->first is a badptr and so it fails the if condition below is. What's wrong here? Running on vc9 express edition on xp64 (the program is 32bit)
An iterator returned as map::end by map::find() means that the specified key was not found in the container. You cannot dereference it to access its elements. It will crash your application.
EDIT:
Let's be clear. The problem is that you are inverting the logic, ok? You can only use an iterator if it's valid, therefore iter must be different from map::end. This means that map::find() was successful and found the element you were looking for:
if (iter != imageMap->end())
{
// element FOUND! Use it!
cout << iter->first << endl;
}
else
{
// Not found! Can't use it.
}
Your mistake is the if comparison you're currently doing: if (iter == imageMap->end()) which means execute the following block of code if the element I searched for is not in the map. That's why when iter->first is executed the application breaks.
#include <iostream>
#include <map>
#include <string>
typedef int ImageData;
typedef std::map<std::string,ImageData*> ImageDataMap;
typedef std::map<std::string,ImageData*>::iterator ImageDataIterator;
using namespace std;
int main()
{
ImageDataMap mymap;
int value_1 = 10;
int value_2 = 20;
int value_3 = 30;
mymap["a"] = &value_1;
mymap["b"] = &value_2;
mymap["c"] = &value_3;
// Search/print valid element
ImageDataIterator it = mymap.find("a");
if (it != mymap.end()) // will execute the block if it finds "a"
{
cout << it->first << " ==> " << *(it->second) << endl;
}
// Searching for invalid element
it = mymap.find("d"); // // will only execute the block if it doesn't find "d"
if (it == mymap.end())
{
cout << "!!! Not found !!!" << endl;
cout << "This statement will crash the app" << it->first << endl;;
}
cout << "Bye bye" << endl;
return 0;
}
Perhapes you should change if(iter == imageMap->end()){...} to if(iter != imageMap->end()){...}