How can I fix an assertion failure that states 'vector subscript out of range' [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
Other questions that I viewed before posting this question:
Debug Assertion Failed: Vector subscript out of range
Debug Assertion Failed Vector Subscript Out of Range C++
I am working on a Boids project, details of which can be found here:
https://www.red3d.com/cwr/boids/
From what I can gather my issue is something to do with an index getting accessed by the function but no data is present in the index. I had this issue yesterday in a different area of my code and fixed it by making one of my getters return a reference rather than a copy of a class object. That approach seems to not be the issue today.
Below is my code:
This code is a snippet from my function that handles simulation events. This is the code that I have narrowed down the issue to.
//Remove flocking organisms with < 0 enery storage.
for (int i = 0; i < m_flock.getSize(); i++)
{
if (m_flock.getOrganism(i).getEnergyStore() <= 0)
{
m_flock.removeOrganism(i);
//m_notFlocking.flock.erase(m_notFlocking.flock.begin() + i);
cout << "Organism died and has been removed..." << endl;
}
}
The code below is from my Flock.cpp class definition file which details information on storing boids in a vector to then apply flocking behaviors to. This class function is giving the following error:
Unhandled exception at 0x7B87FC66 (ucrtbased.dll) in EvoSim.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.
Code:
Organism &Flock::getOrganism(int i)
{
return flock[i];
}
My suspicion is that the for loop size is not reflecting the recently erased object.
How can I fix the vector subscript error?
Edit:
This is the break point that shows up in the debugger:
_NODISCARD _Ty& operator[](const size_type _Pos) noexcept /* strengthened */ {
auto& _My_data = _Mypair._Myval2;
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(
_Pos < static_cast<size_type>(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return _My_data._Myfirst[_Pos];
}
Edit 2:
I did some messing around and discovered the issue only occurs when I run VS 2019 in debug mode, otherwise in Release mode it works fine and as expected.

I see nothing in this code that can cause an out of bounds access. However, you should not increment i on any loop iteration that removes an organism, otherwise you will skip the next organism in the list.
Imagine on the 1st loop iteration, the organism at index 0 needs to be removed. Subsequent organisms move down the list. On the next loop iteration, i gets incremented to 1, and the organism that had moved into index 0 is skipped.
Try this instead:
//Remove flocking organisms with < 0 enery storage.
for (int i = 0; i < m_flock.getSize(); )
{
if (m_flock.getOrganism(i).getEnergyStore() <= 0)
{
m_flock.removeOrganism(i);
cout << "Organism died and has been removed..." << endl;
}
else
++i;
}
Alternatively, you can replace the entire loop using the erase-remove idiom via std::remove_if() and std::vector::erase(), eg:
void Flock::removeDeadOrganisms()
{
//Remove flocking organisms with < 0 enery storage.
flock.erase(
std::remove_if(flock.begin(), flock.end(),
[](const auto &o){ return o.getEnergyStore() <= 0; }
),
flock.end()
);
}
...
m_flock.removeDeadOrganisms();
Or, in C++20, via std::erase_if(), eg:
void Flock::removeDeadOrganisms()
{
//Remove flocking organisms with < 0 enery storage.
std::erase_if(flock,
[](const auto &o){ return o.getEnergyStore() <= 0; }
);
}

To loop though a vector that you are also modifying you don't want to i++ on every loop, since if the element was removed you don't need to increment the index. There are two solutions to this, either you can conditionally increment the index at the end of the loop or you can loop though the list backwards.
int i = 0;
while (i < m_flock.getSize())
{
if (m_flock.getOrganism(i).getEnergyStore() <= 0)
{
m_flock.removeOrganism(i);
cout << "Organism died and has been removed..." << endl;
}
else
{
i++;
}
}
for (int i = m_flock.getSize(); i ; i--)
{
if (m_flock.getOrganism(i).getEnergyStore() <= 0)
{
m_flock.removeOrganism(i);
cout << "Organism died and has been removed..." << endl;
}
}
You can't use a normal iterator loop for this because vector::erase "Invalidates iterators and references at or after the point of the erase, including the end() iterator". However, you can use std::remove_if.
m_flock.erase(std::remove_if(m_flock.begin(),
m_flock.end(),
[](Organism org){
return org.getEnergyStore()<=0;
}));

Related

bool vs void vs print or std::cout [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
What is the difference between having a void or a bool and why is the answer not displaying right? The more I look up and try to understand the deeper I dig myself into a whole. (eg: std::boolalpha)?!?
#include <iostream>
#include <stdio.h>
#include <vector>
bool findPair(int* arr, int arrLength, int k)
{
for(int i=0; i<arrLength; i++)
{
for(int j = i+1;j<arrLength; j++)
{
if(arr[i] + arr[j] == k)
{
printf("Pair Found (%d, %d)", arr[i], arr[j], "\n");
//return;
}
}
}
printf("Pair NOT Found!");
//return false;
}
int main()
{
int array[5] = {4,5,1,7,2};
int sum = 221;
int arrLength = sizeof(array)/sizeof(array[0]);
findPair(array, arrLength, sum);
std::cout << std::endl << findPair() << std::endl;
// return 0;
}
Gives the following output when a pair is found (int sum = 3;):
Pair Found (1, 2)Pair NOT Found!
1
And this output when the pair is not found (int sum = 221;):
Pair NOT Found!
1
Right now, you've told the compiler that findPair returns a bool, but the method doesn't actually return true or false. You've lied to the compiler, and the compiler is allowed to do whatever it wants in this case. A function with a return type should always have a return statement that tells the compiler what value to return to the caller (or throw an exception).
A method with a void return type does not have to have a return; statement, and it's return; statements do not have to return a value, but you can still use return; statements to tell the computer to stop executing the method and return to the caller.
In your case, since you've eliminated the return statement after "Pair Found (%d, %d)", the method keeps executing, until it reaches the end of the loop, which is why you see both printf statements execute. Make sure to put a return type there.
Separately, std::cout << findPair will try print the address of the function, but since there's no overload for that, it will convert the pointer to a boolean, thus printing 1. What you probably wanted was to store the returned value into a bool variable, and send that to cout?
If you want to output true or false instead of 1 or 0 for bool types, then stream out std::boolalpha first, as in std::cout << std::boolalpha << myBoolean;

method giving app crashes due to segmentation fault in c++

this simple loop method is unable to run and an error arises "app crashed". when i checked this in an online compiler it gave 'segmentation fault(core dumped)'-
string studies(setMatter ch) {
string a = "LISTEN CAREFULLY!\n";
int i = 0;
while (i <= ch.a.quantity()) {
a += ch.a.getAns(i);
i++;
}
return a;
}
also see for reference of methods in the above code-
class Answer {
private:
vector<string> ch;
public:
void setAns(string ans) { ch.push_back(ans); }
string getAns(int num) { return (ch[num]); }
int quantity() { return ch.size(); }
};
am i accessing elements out of bond? but i dont know where as i every number starts from 0 in programming
Yes you are.
while(i<=ch.a.quantity()){
should be
while(i<ch.a.quantity()){
Valid vector indexes are zero up to the size of the vector minus one. That should be obvious, if the valid indexes started at zero and went to the size of the vector then there would be one more valid index than the size of the vector, which makes no sense.
Generally you use a for loop for this kind of task
for (int i = 0; i < ch.a.quantity(); i++) {
a += ch.a.getAns(i);
}
It's a little easier to read that way.

C++ There is a bool return type function returning (24) here

First of all sorry for too much code
Here there is a vector (teamNum) with type class, the class contain a vector (player) with type struct, it is a little complicated, but here in this function I need to check if there is a player in teamNum which contain tName equal to _tname (function parameter) contain (the player) pID equal to _pID (function parameter)
bool thereIsSimilarID(string _tname, int _pID)
{
for (int i = 0; i < teamNum.size(); i++)
{
if (teamNum[i].tName == _tname)
{
for (int j = 0; j < teamNum[i].player.size(); j++)
{
if (teamNum[i].player[j].pID == _pID)
return true;
}
}
else if (i == (teamNum.size() - 1))
{
return false;
}
}
}
And in the main
int main()
{
cout << "\n" << thereIsSimilarID("Leverpool", 1) << endl;
}
The output is 24 !!!!!
(good note that this happen just when the team (Leverpool) is the last team in the vector teamNum)
Again sorry for too much code but I need to know the bug not only fix the problem I need to learn from you
You encountered undefined behaviour.
If you take the if (teamNum[i].tName == _tname)-branch on the last element, but find no player with the correct pID, you don't return anything. Which means, that the return value is whatever random value is currently in the memory location that should hold the return value. In your case it happens to 24. But theoretically, everything could happen.
The same problem occurs when teamNum is empty.
The solution is to make sure to always return a value from a function (except if it has return type void of course):
bool thereIsSimilarID(string _tname, int _pID)
{
for (int i = 0; i < teamNum.size(); i++)
{
// In this loop return true if you find a matching element
}
// If no matching element was found we reach this point and make sure to return a value
return false;
}
You should take a look at your compiler settings and enable all the warnings. And often it's good to let it treat certain warnings as errors.

Taking in array of unknown size in c++

Ok I am extremely new to programming, and I am taking a c++ class. Basically for the current project I have to take in an array of unknown size, resize it, and output a bunch of statistics like average, Q1, Q3, etc. I am having trouble taking in the array from the user. I need to quit taking in variables once they enter 0. Here is what I have:
int i = 1; //When I first posted this I didn't mean to comment out the '= 1' part
do {
cin >> array[i];
if (array[i] != 0)
return true;
} while (true);
What am I doing wrong? the program stops after I enter 1 number every time no matter what number I enter.
I am using vector class btw.
Do the following:
// change int to your type
int val;
std::vector<int> vec;
while(std::cin >> val) {
if(val == 0) break;
vec.push_back(val);
}
Reason: Stating a return clause causes to exit the loop.
use of std::vector ensures the arbitrary size condition.
Update after #nonsensickle's constructive remark:
The following piece of code also ensures the only 0 terminates input process condition:
// change int to your type
int val;
std::vector<int> vec;
do {
if(std::cin >> val) {
if(val == 0) break;
vec.push_back(val);
} else { // fix broken input stream in case of bad input
std::cin.clear();
std::cin.ignore(1,'\n');
}
} while(true);
and a more sophisticated way, although overkill but what the hell :), with templates and type traits:
template <typename T>
struct zero_traits
{
static T getzero() { return T(0); }
};
template <>
struct zero_traits<std::string>
{
static std::string getzero() { return "0"; }
};
template <>
struct zero_traits<char>
{
static char getzero() { return '0'; }
};
template <typename T>
std::vector<T> read_values()
{
T val;
std::vector<T> vec;
do {
if(std::cin >> val) {
if(val == zero_traits<T>::getzero()) break;
vec.push_back(val);
} else {
std::cin.clear();
std::cin.ignore(1,'\n');
}
} while(true);
return vec;
}
int main()
{
// change int to your type
std::vector<int> vec = read_values<int>();
for(auto i : vec) std::cout << i << std::endl;
}
First of all i will never increment.
Second of all, if (array[i] != 0) will return if that array's value doesn't equal 0.
You need to read into how do { ... } while() loops work as well as what return statements do. Might as well throw in how to increment an array while you're at it.
I will not try to answer your question directly. What you have is a small logic error and a misunderstanding of the do {...} while () looping construct. What you need is to learn how to step through your code.
Let's go through your code line by line (there are only 6 lines here so it should be really easy):
int i; - Ok, so we are declaring an integer i here but are not giving it a value. As such, i can have a random value.
do { - This is where we will come back to when we evaluate the while clause. But only if the result of the while clause is true.
cin >> array[i] - Store a value that the user enters in the array at the position i. Here we ask ourselves a question, what is i? We should know its value without having to run the program. Hint: there's a problem here because of i
if (array[i] != 0) - If the number entered by the user is not zero return true (exit this function with the result true).
} while (true); - Go back to the do { line and redo all the steps until you get here. There is no condition here so it will keep happening until we exit this function.
Hint: The only exit point of your loop is at step 4.
With this, you should be able to figure out your problem. Trying to break down the problem for yourself should be your first step.
I recommend reading this blog post on debugging small programs. It should be informative.
Though code posted by others (in particular #DimitriosBouzas) will work, and is the better choice, I strongly recommend fixing your code and learning why it failed. This will help you in the long run more than #DimitriosBouzas' elegant solution.
Before answering your question.
Initialize your variables int i=0; .You assign i to be zero because arrays are zero indexed.
You have to incerement i. If do not increment it, i will point at the first "bucket" in your array the whole time. Use i++ or i = i + 1 after every iteration of the do while loop to move "forward" in your array.
You want your program to run until zero is entered so you have to write your condition like this if (array[i] == 0) return true;. This condition is true when the last number entered was zero and it will cause your method to return. It would be more elegant for you to check for it in the while clause.
Putting it all together, your code should look like this
int i=0;
do {
cin >> array[i];
if (array[i] != 0) break;
i++;
} while (i < maxSize);
//do stuff with filled array

dynamic_bitset, crash my program

I'm new with boost. I have a program which uses dynamic_bitset inside a lambda function. After I try to run the program, I get this message. This message appears even without the function that initializes the bitset and the functions that handle it.
Does anybody know what this message means and what might be the problem?
The message:
/usr/include/boost/dynamic_bitset/dynamic_bitset.hpp:616: boost::dynamic_bitset<Block, Allocator>::~dynamic_bitset() [with Block = long unsigned int, Allocator = std::allocator<long unsigned int>]: Assertion 'm_check_invariants()' failed.
Aborted
well the code is something like this
main call to this function :
int Molecule::initSimilarity(int depth){
cout << "_size is: " << _size << "\t depth is: " << depth << endl; //TODO delete
AtomSet viewing(_size);
int m = 0;
{
// break into initial groups by symbol and valancy
for(int i=0 ; i<_size ; i++)
{
if(viewing[i]) continue;
AtomSet mask = getSetMask( //AtomSet is typedef for dynamic_bitset
[&](const Atom& b)->bool
{
return (!viewing[b._index] && b._valence == _atoms[i]->_valence && strcmp(b._symbol, _atoms[i]->_symbol) == 0);
},
[&](Atom &b)
{
b._class = m; //set the equivalence class of atom 'b' to 'm'
}
);
m++;
viewing |= mask; //viewing now contains a set of atoms and for each atom it's equivalence class
}
cout << "number of equivalence class: " << m << endl; //TODO DELETE!
}
for (int j = 0; j < depth ; j++){
AtomSet viewed(_size);
int before = m;
// iteratively refine the breakdown into groups
for (int i = 0 ; i < _size ; i++) //for any atom A
{
if (viewed[i]) continue;
viewed.flip(i);
AtomSet mask = getSetMask(//put all atoms which are equivalnt but not similar to A in
//their own equivalence class
[&](const Atom& b)->bool
{
if (viewed[b._index])
return false; //if b is in viewed return false;
if (_atoms[i]->_class == b._class) //if in the same class add b to viewed
{
viewed.flip(b._index);
bool similar = !isSimilar(*_atoms[i],b);
return similar;
}
return false;
},
[&m](Atom& b)
{
b._class = m;
}
);
if (!mask.none()) m++;
}
if (before == m){
std::cout << "Finished early after just " << j << " iterations" << std::endl;
return m;
}
}
return m;
}
the signature of getSetMask is:
AtomSet getSetMask(std::function property, std::function action);
and the weirdest thing that even when i remove all the content of that function it still give me the error message
Probably the dynamic_bitset variable that you are referencing in the lambda has gone out of scope and has already been destroyed, or something similar. (Without the source code it's difficult to be more specific)
I had that problem and it took me 3 hours to find out the problem. Here is what can happen: The operator[] in dynamic_bitset does not do bound checking. So, one value can be assigned outside of allowed range and this does not create any error (sanitizer/valgrind do not see anything) since dynamic_bitset is using 64 bit integers (on my computer at least) in order to store values. So, you can get a stored integer of 32 while you allowed only 4 bits in the dynamic_bitset. The error is triggered at a later time when m_check_invariant() is called for example when the destructor is called.
So, the problem becomes to find this range error. The solution is to edit the boost/dynamic_bitset.hpp and add print statement in the code of operator[] when an operation out of range is called. If you cannot do that then download the boost library and install it in your home directory.
I had a similar problem with dynamic_bitset that was solved by calling reset() on it before it got destroyed.
That can indicate that you are writing past the end of the bitset without resizing it. Might want to do some bounds checking.
Read the explaination of Mathieu Dutour Sikiric. The problem is that you write outside of allowed range of the bitset via operator[] and this does not create any error because it's boost and it doesn't bother to waste compute time checking that you have right to write where you want. It is C++ you know...
So to detect it, go to boost/dynamic_bitset/dynamic_bitset.hpp, and modify the code to impose checks every time you use operator[].
boost/dynamic_bitset/dynamic_bitset.hpp, around line 300.
reference operator[](size_type pos) {
assert(m_check_invariants());
return reference(m_bits[block_index(pos)], bit_index(pos));
}
bool operator[](size_type pos) const {
assert(m_check_invariants());
return test(pos);
}
This makes it easier to detect the error in your code.