从存储在向量中的指针获取对象属性
Getting object properties from a pointer stored in a vector
紧凑型描述
我很难找出问题所在,因为一些模糊的原因,我将指针存储在向量中的对象的属性似乎发生了变化。
详细说明
我有一个兔子类,它看起来像这样:
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<Rabbit*>
的指针矢量
vector<Rabbit*> rabbits = vector<Rabbit*>(0);
我用它来存储指向新创建的兔子的指针。我将指向新创建的兔子的指针传递给这个向量,如下所示。
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
我的意图是,每当兔子像这样跳出来时,都能解放记忆。(我希望这是正确的方式(
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);
}
}
此处为
Rabbit* adam ;
adam = new Rabbit();
adam->setSexe(Rabbit::MALE);
rabbits.push_back(adam);
delete adam ;
vector
中有一个悬空指针。vector
只深度复制用作vector
参数的类型的对象——在您的情况下,它是Rabbit*
,而不是Rabbit
。所以只复制指针,不复制对象。
稍后,您将检索并使用那个悬空指针,它将调用未定义的行为。
您似乎正在尝试用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
。由于内存位置已被系统标记为已释放,因此将检测到错误,并立即停止您的程序。
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);
您只需将分配内存开始的变量添加到向量中!您不分配新的&复制正因为如此,之后
delete adam ; //i think we dont need the pointer anymore as we copied it to the vector
它释放内存,在第一个字符串中分配。但在向量中,指针并没有改变,因为它只是可变的。所以你不能在这里释放内存,就在你需要删除rabbit的时候。
一些建议:1( 你创建了枚举性别,那么为什么可变性别是int呢?如果会更好:
sexes sex;
2( 不要使用指针(如果不是某个测试项目(,请使用boost::shared_ptr、boost::scoped_ptr。这更安全。
- 我可以使用 decltype() 或其他东西通过指针获取真实类型吗?
- 通过基类指针获取派生类对象的引用
- C++从双指针获取数据
- 如何从原始指针获取shared_ptr?
- 如何从C++中的字符指针获取子字符串
- 使用 std::launder 从指向非活动工会成员的指针获取指向活动工会成员的指针?
- 使用我的共享指针获取内存泄漏
- 通过指向非多态类型的基类的指针获取已分配内存的地址
- 指向引用的指针获取器
- 使用 std::launder 从指向非活动对象的指针获取指向活动对象成员的指针?
- CPP:无法使用 -> 通过指针获取成员的值
- 字符串十六进制到指针获取值
- 从基类指针获取模板派生类的值
- 从 C++ 数组元素的指针获取索引的最快方法是什么
- 通过指针获取最大数量的元素
- 如何使用指针获取字符串数据
- 返回指向指针数组的指针获取下一个元素失败
- 从"子项"项指针获取"父""std::tuple"
- 从成员函数指针获取方法的返回类型
- 如何从指向数组的指针获取对该数组的引用