我有一个问题是找出什么是错的,由于一些模糊的原因,我将指针存储在矢量中的对象中的属性似乎被改变了。
我有一个看起来像这样的兔子。
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 );
}
现在它是一个非常基本的类,析构函数仍然是空的,它有一些属性。 我还有一个vector
类型的指针检测器vector<Rabbit*> rabbits = vector<Rabbit*>(0);
我用它来存储指向新创建的兔子的指针。 我向这个矢量指出了新创建的兔子的指针。
Rabbit* adam ;
adam = new Rabbit();
adam->setSexe(Rabbit::MALE);
rabbits.push_back(adam);
delete adam ; //i think we dont need the pointer anymore as we copied it to the vector
我的意图是每当兔子像这样弹出时释放记忆。 (我希望这是正确的方式)
Rabbit* dead_rabbit = rabbits.back(); //obtain the pointer
delete dead_rabbit ; //free the associated memory
rabbits.pop_back(); //delete the pointer itself
但是当我尝试访问兔子的性属性时,我遇到了麻烦,因为指针已存储在矢量中
Rabbit* rabbit_p = rabbits.at(r) ;
cout << rabbit_p->sex << endl ; // prints a verry high number instead of 1 or 2
所以我的问题是为什么会发生这种情况,我是不是在不知不觉地引用堆中的另一个地方并读出另一个值?为什么?
下面我将包括整个源代码,它远非正确的兔子行为;)但我想测试对象的动态内存分配。起初,矢量只包含普通的兔子,但内存没有被释放,所以现在我正在测试指针方法。
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);
}
}
答案 0 :(得分:3)
下面
Rabbit* adam ;
adam = new Rabbit();
adam->setSexe(Rabbit::MALE);
rabbits.push_back(adam);
delete adam ;
你在vector
内有一个悬空指针。 vector
仅深度复制用作vector
参数的类型对象 - 在您的情况下为Rabbit*
,而不是Rabbit
。所以只复制指针,而不是对象。
稍后您将检索并使用该悬空指针,并调用未定义的行为。
答案 1 :(得分:1)
您似乎正在尝试使用C ++编写Java。
您的问题位于此处:
Rabbit* adam ;
adam = new Rabbit();
adam->setSexe(Rabbit::MALE);
rabbits.push_back(adam);
delete adam ;
new Rabbit
,分配足够的内存来存储你的Rabbit,调用Rabbit的构造函数并返回一个包含你的Rabbit存储地址的指针(假设它是0x42424242)。
然后将此地址复制到向量中,该向量现在包含一个指针(即地址):0x42424242。
当你调用delete adam
时,delete会调用Rabbit的析构函数来存储给定地址的实例,然后将我们之前被Rabbit占用的区域标记为空闲。现在,0x42424242处的内存区域不再存储Rabbit
。
您将此地址保留在向量中,仍然认为其中有Rabbit
,但它指向的位置现在无效。它被称为悬空指针
如果您尝试在向量中使用指针,则可能(或可能不)获取错误,具体取决于内存位置0x42424242中包含的内容。从理论上讲,任何事情都可能发生。
每次触发错误的是尝试在向量中的任何指针上调用delete
。由于系统已将内存位置标记为已释放,因此将检测到错误并立即停止您的程序。
答案 2 :(得分:0)
Rabbit* adam ;
adam = new Rabbit();
adam->setSexe(Rabbit::MALE);
rabbits.push_back(adam);
delete adam ; //i think we dont need the pointer anymore as we copied it to the vector
这是你的错误。 看:
adam = new Rabbit();
你为对象获得了一些内存,并获得了指向它的指针。
rabbits.push_back(adam);
你添加到vector只是变量与分配内存的开始!你没有分配新的&amp;复制。 因为它,在
之后delete adam ; //i think we dont need the pointer anymore as we copied it to the vector
它释放内存,在第一个字符串中分配。但是在向量指针中没有改变,因为它只是变量。 所以你不能在这里释放记忆,就像你需要删除兔子一样。
一些建议: 1)你创建了enum sexes,那么为什么变量性别是int?如果它会更好:
sexes sex;
2)不要使用指针(如果它不是某个测试项目),请使用boost :: shared_ptr,boost :: scoped_ptr。它更安全。