C++ code works fine on desktop but not on the laptop - c++

This simple code for some reason works perfectly fine on my desktop but when I try it on my laptop only the first part (printing the elements of vector) works then the program ends and instead of saying "Process finished with exit code 0" it says
"Process finished with exit code -1073741819 (0xC0000005)". I don't know what's wrong with my laptop. Can anyone help me?
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> array{1, 2, 3, 4, 5};
vector<int>::iterator it;
int arraysize;
for (int i = 0; i < array.size(); i++) {
cout << array[i] << endl;
}
cout << " " << endl;
for (it = array.begin(); it < array.end(); it++) {
if(*it%2==0){
array.erase(it);
it--;
}
}
arraysize=array.size();
cout<<"size:"<<arraysize<<endl;
for (int i = 0; i < array.size(); i++) {
cout << array[i] << endl;
}
return 0;
}

The problem is not with the computer but with the code.
array.erase(it); invalidates the iterator it, and any subsequent use of it has undefined behaviour.
The worst kind of undefined behaviour is the one that appears to work.
erase returns an iterator to the element after the erased one, and you should use that.
for (it = array.begin(); it < array.end(); it++) {
if(*it%2==0){
it = array.erase(it);
it--;
}
}
or
it = array.begin();
while (it < array.end()) {
if(*it%2==0){
it = array.erase(it);
}
else {
it++;
}
}

This happens because of iterator invalidation, when you erase an element of the vector the iterator it becomes invalidated leading to undefined behaviour, you can read more about this here Iterator invalidation rules

Your program has undefined behaviour, you decrement an invalid iterator
array.erase(it); // it becomes invalid
it--; // Undefined
You can avoid this by removing elements with the "erase-remove" pattern
auto is_even = [](int i) { return i%2==0; };
array.erase(std::remove_if(array.begin(), array.end(), is_even), array.end());
Or in C++20
std::erase_if(array, is_even);

There is nothing wrong with your laptop. The problem is with the code. When you erase something from the vector, it invalidates the preexisting iterators following the erased elements. You may want to use the return value of erase, which references the new reallocated location of the erased element's successor.

Related

any clear explanation of this?

I'm trying to learn C++ vectors.. Here is the code:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector <int> vec;
for(int i=0; i<=10; i++){
vec.push_back(i);
}
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
}
Can anybody tell me what this part is?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
I've searched the Internet but couldn't find a clear explanation.
Ok, it prints the numbers that we put it in the vector, but can I get a more technical explanation?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
This is just the iterators in C++.
begin() function is used to return an iterator pointing to the first element of the vector.
Similarly, end() function is used to return an iterator pointing past the last element of the vector.
auto just deduces the type of the variable i. You could have also specified it as std::vector<int>::iterator i = vec.begin() . That's the type of the iterator you are using to loop over the vector.
In the above piece of code, you are basically iterating from the beginning of the vector until the end of the vector.
Inside the loop, you are just dereferencing the iterator and printing the value at the current position where the iterator is.
What the above piece of code is doing is basically the same as the following type of loop, which uses indexing to loop over the array:
for(size_t i = 0; i != vec.size() ; i++){
cout << vec[i] << " ";
}
You should read more about iterators, as they are a core concept in C++. You can read more about them here:
iterators
std::vector.begin()
std::vector.end()
This is an iterator to the first element in the vector: vec.begin()
An iterator to one-past the last element of the vector: vec.end()
auto deduces the type of i from vec.begin(), its an iterator. We really do not need to care about the exact type.
We only need to know that we can increment it: i++.
And compare two iterators with each other to check if we are at the end: i != vec.end().
And we can derference iterators to get the element the "point to": *i.
Without iterators the loop could be written as:
for (size_t i=0; i<vec.size(); ++i) {
std::cout << vec[i];
}
That part simply prints all the elements of the vector. auto automatically determines what data structure it is given the parameters that define it. In this case, it is being used as a vector<int>::iterator. Mostly, this is used in other data structures, such as a map or a set, since those don't support random access. In a vector, you can simply do
for(int i = 0; i < vec.size(); i++)
{
cout << vec[i] << " ";
}

Comparing iterators crashes program without errors in custom bubble sort implementation

I'm relatively new to C++. I have been trying to use iterators to sort a vector. I'm using bubble sort. I don't want to know if my bubble sort implementation works or not, I just want to know what's crashing my program.
template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter &j = end; j != start; j--) {
for (iter &i = start; i != end; i++) {
// std::cout << *i << std::endl;
if (*i > *(i + 1)) { // this line is where it stops
std::iter_swap(i, i + 1);
}
}
}
std::cout << "ended"; // this line never gets called
}
When the program stops, though, it doesn't show any exceptions. I also try-catched the part where it stopped, but it didn't go in the try catch. Also, whenever I un-comment the first printing line:
std::cout << *i << std::endl;
It prints 1168169449 forever. What is going wrong here?
I'm testing it like this:
std::vector<int> vector = {1, 2, 3, 6, 4, 5};
std::vector<int> temp = vector;
//std::sort(temp.begin(), temp.end());
bubbleSort(vector.begin(), vector.end());
for(auto& num : vector) {
std::cout << num << std::endl;
}
In that line you are dereferencing i + 1, in the last iteration of the cycle it will dereference .end() which invokes undefined behavior, .end() is one past the last element, it can't be dereferenced.
Quick fix is to make your stop condition i != end - 1.
This, though will not fix the the bubble sort implementation which would still be flawed for more complex sequences, take this sample vector:
std::vector<int> vector = {1, 2, 7, 3, 6, 4, 5};
As you can see here, it will not be sorted correctly.
A possible correction would be:
Demo
template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter i = start + 1; i != end; i++) {
for (iter j = start; j != end - 1; j++) {
if (*i < *j) {
std::iter_swap(i, j);
}
}
}
std::cout << "ended" << std::endl;
}
This version, though it works as intended, could be optimized, you could do away with one of the copies at the cost of a slightly less readable code and optimize the number of iterations:
template<typename iter>
void bubbleSort(iter start, iter end) {
while(start != end) {
for (iter j = start; j != end; j++) {
if (*start > *j) {
std::iter_swap(start, j);
}
}
start++;
}
std::cout << "ended" << std::endl;
}
Another thing you could do is to add a condition do to avoid dereferencing and comparing values in the same position, removing some overhead whith less indirection calls.
//...
if(start == j){ // will compare the iterators and skip the loop if they are equal
continue;
}
//...
All things considered, I would use something like this:
template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter i = start; i != end; i++) {
for (iter j = i; j != end; j++) {
if(i == j) {
continue;
}
if (*i > *j) {
std::iter_swap(i, j);
}
}
}
std::cout << "ended" << std::endl;
}
As said in the linked thread, performance is deppendant of several factors among which are the CPU architecture, the SO or the compiler, you must test these solutions and see which one gives you the best performance.
You can also use your compiler optimization options to adjust the compilation to your needs.
You are dereferencing the end iterator which you cannot dereference.
In your loop you go through each iterator until the end. Problem is, you plus the iterator each time. When the iterator is equal to end - 1 and you add that one to it you will receive end which you then dereference. This is undefined behaviour, thus the random number.
You could try changing the loop condition to be != end - 1 which would mean i + 1 could never be end.

Decrementing iterator after each loop iteration shows weird behavior

I created a program to try to practice on the semantics of the list data structure. I noticed a weird difference in the following pieces of code:
First code:
#include<iostream>
#include<list>
using namespace std;
int main() {
list<int> l;
int n = 100;
for(int i = 0; i < n; i++) {
l.push_back(i);
}
list<int>::iterator it = l.end();
it--;
for(; !l.empty(); it--) {
cout << "the size of l is " << (int) l.size() << endl;
l.erase(it);
}
}
Second code:
#include<iostream>
#include<list>
using namespace std;
int main() {
list<int> l;
int n = 100;
for(int i = 0; i < n; i++) {
l.push_back(i);
}
list<int>::iterator it = l.end();
it--;
for(; !l.empty();) {
cout << "the size of l is " << (int) l.size() << endl;
l.erase(it--);
}
}
The objective of both pieces of code is simple - to simply erase all the elements in a list.
The only difference between them is the place where the list iterator is decremented.
In the first code sample, I used the for-loop control flow to decrement the iterator. In the second, I used the post-decrement operator to decrement the iterator.
Based on my understanding, the above code samples should be equivalent because I decrement the iterator immediately after I erase an element from the list. Furthermore, according to the STL docs, only the iterator to the erased element in the list is invalidated. So there should not be any undefined behavior.
The problem is, the second code sample works as expected - it stops after erasing all elements in the list. However, for the first sample, the list size could even become negative?! When I tried increasing the initial number of elements in the list, the first program crashes halfway.
Could someone kindly advise me on why these code samples behave differently?
The 1st code has undefined behavior. As you said, erase makes the iterator invalid, the it-- evaluated after that leads to UB.
The 2nd code is fine; note the evaluation order is different. it-- will decrement the iterator, then return the original value (that's the point of post-decrement operator). The original value is passed to erase later. Decrement happens before erase so it's fine.

Vector Iterator not dereferencable (trying to manually reverse vector)

I'm trying to create a function which takes in a vector and simply reverses (manually). I'm aware of the existence of reverse(), but I ran into the "Vector iterator not dereferencable" problem and for educational purposes, I'd like to know what it means. I tried researching this problem and someone (on this forum) said that vect.end() is not dereferencable by definition, but from my understanding, using reverse_iterator is just reversing the ends, so following the logic; vect.rend should not be dereferencable.
vector<int> reverseVector(vector<int>);
int main()
{
vector<int> vec;
for (int i = 0; i < 11; i++)
{
vec.push_back(i);
}
vec = reverseVector(vec);
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
vector<int> reverseVector(vector<int> vect)
{
vector<int>::reverse_iterator ritr;
for (ritr = vect.rbegin(); ritr != vect.rend(); ritr++)
{
vect.insert(vect.begin(), *ritr);
vect.pop_back();
}
return vect;
}
You are deleting elements from the vector (popping from the back), which invalidates the reverse iterator.
You could just iterate through half of the vector and swap the elements, lke this:
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
vector<int> reverseVector(vector<int> vect) {
const size_t origin_size = vect.size();
for(size_t i = 0; i < origin_size/2; ++i)
swap(vect[i], vect[origin_size - 1 - i]);
return vect;
}
Your problem has nothing to do with the dereferencability or otherwise of rend(). You're modifying the vector while iterating over it, which invalidates the iterator.
To answer your original question, a reverse_iterator isn't just "reversing the ends" compared to a forward iterator. rbegin() is end() - 1, and rend() is begin() - 1.
If you add an element to the vector, ritr may be invalidated thus the error
Vector iterator not dereferencable.
Thus its better using an index as your loop variable or better a copy(temp) vector for reverse task.
Both insert and pop_back member functions modify the vector and invalidate iterators.
A tip as design-issue: use always const-reference in a function, unless you really know what you are doing. So you will avoid stepping in traps like this. For example:
vector<int> reverseVector(const vector<int> &vect)
Now you wont have this problem, because you can not modify vect.

After resize of vector then why can I not increment vector

I am trying to write a data structure that I can cycle round, sort of a circular list, using a vector. I resize which I am thinking should initialise the underlying array with ten elements. I don't understand why I cannot advance the iterator. Can someone please help.
I cannot use push_back() because that will always append to the end which is not what I want.
// re-use start of vector when get to end
#include <vector>
#include <iostream>
#include <algorithm>
using std::cout;
using std::endl;
using std::vector;
class printme {
public:
void operator() (int val) {cout << val << endl; }
};
//get a debug assertion - message says: vector iterators incompatible
//I assume this means that it is invalid after previous it++
int main(int argc, char* argv[])
{
vector<int> myvec;
myvec.resize(10); //underlying array now has size=10 elements
vector<int>::iterator it = myvec.begin(); //point to start of array
for(int i = 0; i < 100; ++i) {
if(it == myvec.end()) //on 2nd iteration crashes here - invalid iterator
it = myvec.begin();
myvec.insert(it++, i);
}
//print contents of vector - check 90-99 printed
for_each(myvec.begin(), myvec.end(), printme());
return 0;
}
EDIT
Changed loop to this:
for(int i = 0; i < 100; ++i) {
if(it == myvec.end())
it = myvec.begin();
*it++ = i;
}
I didn't properly understand insert.
From what you expect in output - I believe you misunderstood what insert is doing.
Implement your loop in this way (without insering - just replacing). std::vector<>::insert increments the size of your vector by one - I believe it is not what you expect.
Do not do this:
myvec.insert(it++, i);
But this:
*it++ = i;
Then you'll get your desired ouput:
//print contents of vector - check 90-99 printed
for_each(myvec.begin(), myvec.end(), printme());
Iterators can be invalidated by some operations on a vector - including insert. You'll need to re-fectch it in order to be able to use it after the insert.
vector<int>::iterator it = myvec.begin(); //point to start of array
for(int i = 0; i < 100; ++i) {
if(it == myvec.end()) //on 2nd iteration crashes here - invalid iterator
it = myvec.begin();
myvec.insert(it++, i);
//it can be invalid here, re-fetch it
it = myvec.begin();
}