Compact description
I’m having a problem to find out what’s wrong, for some obscure reason the properties in an object for which I stored the pointer in a vector seem to be changed.
Detailed explanation
I have a class Rabbit which looks like this:
class Rabbit {
enum sexes { MALE = 0x1, FEMALE = 0x2 } ;
int sex ;
bool has_mated ;
Rabbit();
~Rabbit();
void setSexe(int sex);
void match( vector<Rabbit*> &rabbits );
void breed( Rabbit &partner, vector<Rabbit*> &rabbits );
}
For now it’s a very basic class, the destructor is still empty and it has a few properties.
I also have a pointer vector of type vector<Rabbit*>
vector<Rabbit*> rabbits = vector<Rabbit*>(0);
which I use to store pointers to newly created rabbits.
I’m passing the pointers to newly created rabbits to that vector like this.
Rabbit* adam ;
adam = new Rabbit();
adam->setSexe(Rabbit::MALE);
rabbits.push_back(adam);
delete adam ; //I think we don't need the pointer anymore as we copied it to the vector
my intention is to free memory whenever a rabbit gets popped off like this.
( I hope this is the right way )
Rabbit* dead_rabbit = rabbits.back(); //obtain the pointer
delete dead_rabbit ; //free the associated memory
rabbits.pop_back(); //delete the pointer itself
But I run into trouble when I try to access the sex property of a rabbit for which the pointer has been stored in the vector.
Rabbit* rabbit_p = rabbits.at(r) ;
cout << rabbit_p->sex << endl ; // prints a verry high number instead of 1 or 2
So my question is why does this happen, am I unknowingly referring to another place in the heap and reading out another value? and why?
Below I’ll include the whole source code, it is far from correct rabbit breading behavior, but I wanted to test dynamic memory assignment for objects. At first the vector contained just plain rabbits, but the memory wasn’t released, so now I’m testing the pointer approach.
Complete source
using namespace std ;
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <iterator>
#include <sys/time.h>
#include <sys/resource.h>
class Rabbit {
public:
enum sexes { MALE = 0x1, FEMALE = 0x2 } ;
int sex ;
bool has_mated ;
Rabbit();
~Rabbit();
void setSexe(int sex);
void match( vector<Rabbit*> &rabbits );
void breed( Rabbit &partner, vector<Rabbit*> &rabbits );
};
Rabbit::Rabbit(){
this->sex = random() % 2 + 1 ; //random m/f
this->has_mated = false ;
}
Rabbit::~Rabbit(){
}
void Rabbit::setSexe( int sex ){
this->sex = sex ;
}
void Rabbit::match(vector<Rabbit*> &rabbits){
int s = rabbits.size() ;
int r = 0 ;
for(r ; r < s ; r++ ){
Rabbit* partner_ptr = rabbits.at(r) ;
Rabbit partner = *partner_ptr ;
if( partner.sex == Rabbit::MALE && partner.has_mated == false ){
this->breed(partner, rabbits);
this->has_mated = true ;
partner.has_mated = true ;
break ;
}
}
}
void Rabbit::breed( Rabbit &partner, vector<Rabbit*> &rabbits ){
int offspring, sex ;
offspring = random() % 4 + 3 ;
cout << "breeding " << offspring << " rabbits..." << endl ;
Rabbit* temp_rabbit ;
for(int i=0; i < offspring; i++){
int sex = random() % 2 + 1 ;
temp_rabbit = new Rabbit() ;
temp_rabbit->setSexe(sex);
rabbits.push_back(temp_rabbit);
cout << "one rabbit has been born." << endl ;
}
}
//makes rabbits date each other
void match_rabbits(vector<Rabbit*> & rabbits){
cout << "matching rabbits..." << endl ;
for(int r = 0; r < rabbits.size() ; r++ ){
Rabbit* first_rabbit_p = rabbits.front();
Rabbit* nth_rabbit_p = rabbits.at(r);
cout << "pointer to first rabbit: "<< first_rabbit_p << endl ;
cout << "pointer to rabbit n° " << r << ": " << nth_rabbit_p << "( " << sizeof( *nth_rabbit_p ) << "B )" << endl ;
cout << "sex parameter of dereferenced rabbit: " << rabbit.sex << endl ;
/*
if( rabbit.sex == Rabbit::FEMALE && rabbit.has_mated == false){
cout << "found a female" << endl ;
rabbit.match(rabbits) ;
} */
}
}
void pop_rabbits(vector<Rabbit*> & rabbits, int n){
vector<Rabbit*>::iterator rabbits_iterator ;
for(int r = 0 ; r < rabbits.size() ; r++ ){
Rabbit* rabbit = rabbits.back();
delete rabbit ;
rabbits.pop_back();
}
}
int main( int argc , const char* argv[] ){
srand(time(NULL));
vector<Rabbit*> rabbits = vector<Rabbit*>(0) ;
Rabbit* adam ;
adam = new Rabbit();
adam->setSexe(Rabbit::MALE) ;
Rabbit* eve ;
eve = new Rabbit() ;
eve->setSexe(Rabbit::FEMALE) ;
char * input;
input = new char[2] ;
try{
//populate with 2 rabbits.
rabbits.push_back(adam);
rabbits.push_back(eve);
delete adam ;
delete eve ;
do {
//memory_usage = getrusage(RUSAGE_SELF, struct rusage *usage);
if(rabbits.size() < 2){
break ;
}
cout << rabbits.size() << " rabbits ( " << "K )" << endl ;
cout << "Shoot some rabbits ? (Y/N) :" << endl ;
delete[] input ;
input = new char[2] ;
cin.getline(input,2);
if( strcmp(input,"Y") == 0 || strcmp(input,"y") == 0){
cout << "How many ? :" << endl ;
delete[] input ;
input = new char[16] ;
cin.getline(input,16);
pop_rabbits(rabbits, atoi(input));
continue ;
}
cout << "Continue ? (Y/Q) :" << endl ;
delete[] input ;
input = new char[2] ;
cin.getline(input,2);
if(strcmp(input,"Y") == 0 || strcmp(input,"y") == 0){
match_rabbits(rabbits);//let the rabbits date
}
if(strcmp(input,"Q") == 0 || strcmp(input,"q") == 0){
break ;
}
} while( true );
exit(0);
} catch ( exception& e ){
cout << e.what() << endl ; //print error
exit(1);
}
}
Here’s you have mistake.
Look:
You get some piece of memory for your object, and get pointer to it’s begin.
You add into vector just variable with begin of allocated memory! You don’t allocate new & copy.
Because of it, after
it free memory, allocated in first string. But in vector pointer doesn’t change, because it’s just variable.
So you mustn’t free memory here, just when you need to delete rabbit.
Some advices:
1)You create enum sexes, so why variable sex is int? Better if it will be:
2)Don’t use pointers(if it’s not some test project), use boost::shared_ptr, boost::scoped_ptr. It’s more safety.