I'm having some troubles adding and removing elements from an std::vector (population, in the example code). What I want to do is to erase an element if a condition is satisfied and copy the element if instead other conditions are satisfied. Here's the code:
for( int i = 0; i < walkers_num; i++) {
if( population[i].molteplicity == 0 ) {
population[i] = population.back();
population.pop_back();
i--;
} else {
for( int j = population[i].molteplicity; j > 1; j-- ) {
population.push_back(population[i]);
}
}
}
walkers_num = population.size();
What I get is:
*** error for object 0x7f86a1404498: incorrect checksum for freed object - object was probably modified after being freed.
I guess I'm using some std::vector property in a wrong way, since a very similar algorithm (conceptually they seem identical to me) seems to work if population is instead an std::list:
list<Walker>::iterator it;
list<Walker>::iterator end = thread_population[i].end();
for ( it = thread_population[i].begin(); it != end; ) {
if( it->molteplicity == 0 ) {
it = thread_population[i].erase(it);
continue;
}
for( int j = it->molteplicity; j > 1; j-- ) {
population.push_back(*it);
}
++it;
}
walkers_num = population.size();
Can you help me?
You haven't posted quite enough code.
I'm assuming you omitted at the start of the fragment:
walkers_num = population.size();
And are trying to visit the whole array. In that case try:
walkers_num = population.size();
for( int i = 0; i < walkers_num; i++) {
if( population[i].molteplicity == 0 ) {
population[i] = population.back();
population.pop_back();
i--;
--walkers_num; //Array has been shortened.
}
//....
You seem to have realised the length has changed because you put walkers_num = population.size(); at the end. You need to keep track throughout.
There are subtle reasons why your iterator code is likely to work but technically just as invalid. You're not allowed to assume end is valid after a modification.
Related
I'm currently trying to create a sudoku solver in C++, but I have run into a slight problem. Instead of starting out with a 9x9 sudoku, I've started with a 4x4 one. For every square that can contain a number I am trying to get the possible numbers that square can hold into an array, e.g. if the possibilities in square 3 are 1 and 4,
for ( int i; i < 4; i++ ) {
cout << candidates[3][i];
}
would give me 1004. It is easily accessible when I need to code hard solving methods or a brute force solving method.
Here is the problem: I need to check whether a number occurs in any row, column or (2x2 or 3x3) box, and if it does not, add it to the candidates array. Here's what I thought of:
for ( int i = 0; i < 16; i++ ) {
for ( int j = 1; j < 5; j++ ) {
if ( for ( int k = 0; k < 4; k++ ) { allRows[getRow(i)][k] != j || allCols[getCol(i)] [k] != j || allBoxs[getBox(i)][k] != j}) {
candidates[i][j-1] = j;
}
}
}
The arrays allRows, allCols, allBoxs all contain the sudoku, only in such an order that they are easily accessible when they are needed. The functions getRow(), getCol() and getBox() return the number of the row, column or box (respectively, of course) the input number is in.
I tried to make it loop though everything in the same row, column or box as the number, to get all twelve checked by the if, and if they all passed, then I would add the number to the candidates array.
It came to me as no surprise that it returned an error when I tried to compile this. But I really don't want to write out twelve AND conditions in the if statement, or 27 when I upgrade to 9x9 sudoku, because:
I don't learn anything and
Where's the fun in that?
Can anyone help me / suggest another idea to do this without typing everything out?
I apologize if my inability to be concise hinders an answer to this question, I was only trying to provide all the details I thought maybe were necessary...
Condition of if should be an expression convertible to bool. it is not the case of for-statement.
You might do instead (assuming I correctly understood your condition):
for ( int i = 0; i < 16; i++ ) {
for ( int j = 1; j < 5; j++ ) {
bool b = false;
for ( int k = 0; k < 4; k++ ) {
if (allRows[getRow(i)][k] != j || allCols[getCol(i)][k] != j || allBoxs[getBox(i)][k] != j) {
b = true;
break;
}
}
if (b) {
candidates[i][j-1] = j;
}
}
}
or with helper function
template <typename Range, typename T>
bool contains(const Range& range, constT& value)
{
using std::begin;
using std::end;
return std::find(begin(range), end(range), value) != end(range);
}
// ...
for ( int i = 0; i < 16; i++ ) {
for ( int j = 1; j < 5; j++ ) {
if (!contains(allRows[getRow(i)], j)
|| !contains(allCols[getCol(i)], j)
|| !contains(allBoxs[getBox(i)], j)) {
candidates[i][j-1] = j;
}
}
}
Like you already noticed, adding an for-statement inside of the condition of the if doesn't work. There are several reasons for it, however, let me point out a few that cause confusion:
What if the for-loop wouldn't iterate? Would this result in true or false?
What if you have multiple iterations? Would we && or || the boolean values into it? And how about short cutting of those operators?
Long story short: Even if this would be considered to ever add to the standard, I expect it to be blocked thanks to the many edge cases.
So what does this mean? Is this impossible? Off course not, it's C++. Like already mentioned in the answer of #Jarod42 you can calculate a boolean and than do the if-statement. Or like both of us mentioned (me in the comments), you could move this into a function.
Personally, I've stepped away from remembering state about my for-loop like with this boolean. The main reason: This is hard to read. Every single time you read that code, you need to check what's actually happening.
Hence, I suggest to move this to a function. A function has a clear name and could even be tested separately to ensure it's behavior is correct.
So in this case, I would write something like:
template<typename T1, typename T2, typename T3>
auto checkForExistanceOf(int shouldExist, int locator, T1 &&allRows, T2 &&allCols, T3 &&allBoxs)
{
for ( int k = 0; k < 4; k++ )
{
if (allRows[getRow(locator)][k] != shouldExist)
return true;
if (allCols[getCol(locator)] [k] != shouldExist)
return true;
if (allBoxs[getBox(locator)][k] != shouldExist)
return true;
}
return false;
}
The code on caller side than becomes:
for ( int i = 0; i < 16; i++ )
{
for ( int j = 1; j < 5; j++ )
{
if (checkForExistanceOf(j, i, allRows, allCols, allBoxs))
{
candidates[i][j-1] = j;
}
}
}
For sure, my names ain't that good, as I don't know the exact purpose, nor would I suggest using a template as you know the actual types, though, this is the idea behind it.
I'm trying to "erase" an element from a vector that is itself contained in another vector. However, either I forgot how to do this, I missed the point, or there's a huge oversight. It always erases the very first element in the vector, whatever I try.
void release_docking() {
int loop_R = (int)parent_cell->cells.size();
for (int i = 0; i < loop_R; i++) {
int loop_C = (int)parent_cell->cells[i].size();
for (int j = 0; j < loop_C; j++) {
if (parent_cell->cells[i][j] = this) {
parent_cell->cells[i].erase(parent_cell->cells[i].begin() + j);
if (parent_cell->cells[i].empty()) {
parent_cell->cells.erase(parent_cell->cells.begin() + i);
}
parent_cell = nullptr;
is.docked = false;
resize_cells(root_cell);
break;
}
}
}
}
This line
if (parent_cell->cells[i][j] = this) {
will assign this to parent_cell->cells[i][j] and evaluate to true.
After that it will be erased.
That should be == not =.
Recent compilers should warn you about this. Make sure that warnings are turned on.
I'm having a problem with one of my homework assignments in which we need to detect duplicate strings in a vector of strings using a hash table. My code builds and compiles fine but I get a Segmentation fault when I try to assign the return vector from the duplicate detection algorithm to the duplicates vector. I've tried to figure out why this is happening but can't find a solution. I've attached my code below.
Function to find duplicates using hash table ##
std::vector<std::string>find_duplicates_with_hashtable(std::vector<std::string> & strings) {
std::vector<std::string> dups;
typedef std::unordered_map<std::string, std::string> hashtable;
hashtable table;
for (std::vector<std::string>::iterator i = strings.begin(); i < strings.end(); i++) {
std::unordered_map<std::string, std::string>::const_iterator it = table.find(*i);
if (it != table.end() && (std::find(dups.begin(), dups.end(), *i)) == dups.end()) {
dups = find_duplicates_with_sorting(dups); // line causing the problem
}
table.emplace(*i, *i);
}
return dups;
}
Function used to check if any elements in the given vector are present in the duplicates vector
std::vector<std::string> find_duplicates_with_sorting(std::vector<std::string> & strings) {
std::vector<std::string> dups;
std::sort(strings.begin(), strings.end());
for( unsigned int i = 0; i < strings.size() - 1; ++i ) {
if( strings[i].compare(strings[i+1]) == 0 ) {
std::string found_dup = strings[i];
if( dups.size() == 0 ) {
dups.push_back(found_dup);
}
else
{
std::string last_found_dup = dups[ dups.size() - 1 ];
if( last_found_dup.compare(found_dup) != 0 ) { // Not a dup of a dup
dups.push_back(found_dup);
}
}
}
}
return dups;
}
This is the context in which the hash table function is being called
TEST(BaseHash, SuperShortVector)
{
std::vector<std::string> dups_found;
auto & search_vector = super_short_vector;
auto & known_dups_vector = super_short_vector_dups;
dups_found = find_duplicates_with_hashtable(search_vector);
std::sort(dups_found.begin(), dups_found.end());
std::sort(known_dups_vector.begin(), known_dups_vector.end());
}
The line causing the problem is marked by a comment in the 'find_duplicates_with_hashtable' function
Also, since this is a homework assignment, I would greatly appreciate if someone could explain what I did wrong and just give me a general direction I could work towards in order to fix the problem since just copy-pasting code wouldn't help me learn
Sorry if the code is horrible. I'm having trouble understanding how to use hash tables.
Thank you :)
The segfault is happening here:
for( unsigned int i = 0; i < strings.size() - 1; ++i ) {
if( strings[i].compare(strings[i+1]) == 0 ) {
The issue is that you are comparing an unsigned value, i, with the unsigned value returned from strings.size() - 1. When strings.size() is 0, this part i < strings.size() - 1 will be checking if i is less than the greatest integer value, which will (basically) always be true.
This causes strings[i+1] to segfault when strings is length 0 or 1.
This can be fixed in many ways, but for( int i = 0; i < (int)strings.size() - 1; ++i ) { would be a quick and dirty way to fix it.
So, I read the problem 4.5 from Accelerated C++, and interpreted it rather wrong. I wrote a program which is supposed to display counts of a word in string. However, I have probably done something very stupid, and very wrong. I can't figure it out.
Here's the code: http://ideone.com/87zA7E.
Stackoverflow says links to ideone.com must be accompanied by code. Instead of pasting the all of it, I will just paste the function which I think is most likely at fault:
vector<str_info> words(const vector<string>& s) {
vector<str_info> rex;
str_info record;
typedef vector<string>::size_type str_sz;
str_sz i = 0;
while (i != s.size()) {
record.str = s[i];
record.count = 0;
++i; //edit
for (str_sz j = 0; j != s.size(); ++j) {
if (compare(record, s[j]))
++record.count;
}
for (vector<str_info>::size_type k = 0; k != s.size(); ++k) {
if (!compare(record, rex[k].str))
rex.push_back(record);
}
}
return rex;
}
One problem is that you have this:
str_sz i = 0;
while (i != s.size()) {
but you never increment i, leading to an endless loop. Inside of that loop, you're pushing elements into vector rex. A vector cannot contain an infinite number of elements.
Also, you are trying to access:
rex[k].str
in
for (vector<str_info>::size_type k = 0; k != s.size(); ++k) {
if (!compare(record, rex[k].str)) // rex is empty in the beginning!!
rex.push_back(record);
}
But you do not know whether rex has k+1 elements in it.
EDIT: Change your code to:
while (i != s.size()) {
// read new string into a record (initial count should be one).
str_info record;
record.str = s[i];
record.count = 1;
// check if this string already exists in rex
bool found = false;
for (vector<str_info>::size_type k = 0; k < rex.size(); ++k) {
if ( record.str == rex[k].str ) {
rex[k].count++;
found = true;
break;
}
}
i++;
if ( found )
continue;
// if it is not found then push_back to rex
rex.push_back( record );
}
is there anybody using BWAPI who gets access violation error when accessing the Unit objects of the current game?
i am certain that the error is not in my code.. anyway.. is there anything i can do to avoid access violation?
i am getting this error sometimes at line with the comment bellow.. this code bellow execute many times and only sometimes i get the error..
int Squad::getSize() {
int no = 0;
for (int i = 0; i < (int) agents.size(); i++) {
BaseAgent* agent = agents.at(i);
if (agent != NULL && agent->isAlive() && agent->getUnit() != NULL && !agent->getUnit()->isBeingConstructed()) // this line
no++;
}
return no;
}
this is the code that I use to remove an BaseAgent from the vector.. analyze that and see if i can do it better:
void AgentManager::cleanup() {
//Step 2. Do the cleanup.
int cnt = 0;
int oldSize = (int)agents.size();
for (int i = 0; i < (int)agents.size(); i++) {
if (!agents.at(i)->isAlive()) {
delete agents.at(i);
agents.erase(agents.begin() + i);
cnt++;
i--;
}
}
int newSize = (int)agents.size();
}
the BaseAgent code is on this link
I would speculate that this line:
BaseAgent* agent = agents.at(i);
is returning some invalid pointer which is not set to 0.
Looking at your cleanup code, it looks a bit complicated. I would suggest
looping over the entire vector, deleting the dead elements and
setting the pointers to 0.
After the loop, use the erase-remove idiom to remove all NULL pointers from the vector.
step 1
for (unsigned int i = 0; i < agents.size(); ++i) {
if (!agents.at(i)->isAlive()) {
delete agents.at(i);
agents.at(i) = 0;
}
step 2
agents.erase(std::remove(agents.begin(), agents.end(), 0), agents.end());