我不明白多线程游戏中的对象不匹配
I don't understand the object mismatch in a multithreading game
我正在开发一款多线程游戏。它有 3 个 classes :
Carte
,一张图由几个Case
组成
Batiment
,一条船,几条船互相厮杀。
Case
,是地图的基本单元格,可以用Batiment
链接。
每个线程控制一个 Batiment 对象,一切似乎都很好,但是当我尝试输出游戏时,显示我的不同线程的 ID 号代表地图中的 Batiment
,它没有不工作。它不会打印每个线程,它只会打印我在 main.cpp
中创建的最后一个 Batiment
。
我在上面待了 3 天...
这是我的文件:
main.cpp:
std::vector<Batiment> batiments;
for(int i = 0; i < nbrBatiments; i++){ //Ajout des Batiments sur le vecteur
//Batiment temp = new Batiment(&carte, i);
Batiment temp(&carte, i);
batiments.push_back(temp);
}
for(int i = 0; i < nbrBatiments; i++){
if ((rc = pthread_create(&thread[i], NULL, Batiment::launcher, (void *)&batiments[i]))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc); return EXIT_FAILURE;
}
}
Batiment.cpp: launcher 函数,我用它来传递一个对象给线程:
void *Batiment::launcher(void *context)
{
return static_cast<Batiment*>(context)->jouer();
}
Batiment.h:这里的成员是class
Carte *carteInside;
static void *launcher(void *context);
int id;
void *jouer();
Case.h: 这里是 class 的成员,链接到一个 Batiment 对象:
Batiment *batiment;
我的Batiment::jouer()
方法只是在地图中移动当前对象并射击另一个对象的方法...当我"cout"调用[=26=的对象的当前ID时],所描述的问题发生的地方
Carte.cpp:
for(int i = 0; i<this->x; i++){
for(int j = 0; j<this->y; j++){
if(this->carte[i][j].libre == false){
printf("%d", this->carte[i][j].batiment->id);
}
}
}
carte.h: class
成员
std::vector< std::vector<Case> > carte;
编辑:Batiment
的构造函数:
Batiment::Batiment(Carte *carte, int i) {
this->carteInside = carte;
do{
this->x = doRand(0, carte->x);
this->y = doRand(0, carte->y);
}
while(!carteInside->carte[x][y].libre);
this->id = i;
this->orientation = doRand(0, 3);
this->longueur = doRand(2, 4);
this->vie = 2*(this->longueur)*(this->longueur);
carte->carte[this->x][this->y].libre = false;
carte->carte[this->x][this->y].batiment = this;
}
问题是您通过 Batiment
的构造函数填充 Carte
,但使用了一个被破坏的临时对象,使指针无效:
为什么?
在此语句中,您创建了一个临时 Batiment
:
Batiment temp(&carte, i);
您的构造函数显然会在 Carte::carte[][]
中插入指向新创建对象的指针。
不幸的是,您在 for 循环的块中定义了这个临时值:
for(int i = 0; i < nbrBatiments; i++){ //Ajout des Batiments sur le vecteur
Batiment temp(&carte, i); // <=== L'instance n'existe que le temps d'une itération !!
...
}
所以在这个循环的每一次迭代中都会创建和销毁这个临时文件。所以你的指针一离开循环就失效了。
当您稍后引用它时,它是未定义的行为。它能找到任何有意义的值只是一种运气。
顺便说一下,当你在 vector 中推回 temp 时,将创建对象的副本(相同的值,但仍然是另一个地址)。
如何解决?
嗯,保持你最初设计的想法,有几个解决方案。
最简单的方法是在免费商店中创建您的 Batiment:
Batiment *temp = new Batiment (&carte, i);
唯一的一点就是某天某个地方需要删除该对象。所以要么你在 Carte 的析构函数中处理这个,要么你改变你的 vecotr 以保留一个指针,以便你以后可以删除所有这些对象。
更好的方法是使用 shared_ptr
,它会自行处理内存管理。
我正在开发一款多线程游戏。它有 3 个 classes :
Carte
,一张图由几个Case
组成
Batiment
,一条船,几条船互相厮杀。Case
,是地图的基本单元格,可以用Batiment
链接。
每个线程控制一个 Batiment 对象,一切似乎都很好,但是当我尝试输出游戏时,显示我的不同线程的 ID 号代表地图中的 Batiment
,它没有不工作。它不会打印每个线程,它只会打印我在 main.cpp
中创建的最后一个 Batiment
。
我在上面待了 3 天...
这是我的文件:
main.cpp:
std::vector<Batiment> batiments;
for(int i = 0; i < nbrBatiments; i++){ //Ajout des Batiments sur le vecteur
//Batiment temp = new Batiment(&carte, i);
Batiment temp(&carte, i);
batiments.push_back(temp);
}
for(int i = 0; i < nbrBatiments; i++){
if ((rc = pthread_create(&thread[i], NULL, Batiment::launcher, (void *)&batiments[i]))) {
fprintf(stderr, "error: pthread_create, rc: %d\n", rc); return EXIT_FAILURE;
}
}
Batiment.cpp: launcher 函数,我用它来传递一个对象给线程:
void *Batiment::launcher(void *context)
{
return static_cast<Batiment*>(context)->jouer();
}
Batiment.h:这里的成员是class
Carte *carteInside;
static void *launcher(void *context);
int id;
void *jouer();
Case.h: 这里是 class 的成员,链接到一个 Batiment 对象:
Batiment *batiment;
我的Batiment::jouer()
方法只是在地图中移动当前对象并射击另一个对象的方法...当我"cout"调用[=26=的对象的当前ID时],所描述的问题发生的地方
Carte.cpp:
for(int i = 0; i<this->x; i++){
for(int j = 0; j<this->y; j++){
if(this->carte[i][j].libre == false){
printf("%d", this->carte[i][j].batiment->id);
}
}
}
carte.h: class
成员std::vector< std::vector<Case> > carte;
编辑:Batiment
的构造函数:
Batiment::Batiment(Carte *carte, int i) {
this->carteInside = carte;
do{
this->x = doRand(0, carte->x);
this->y = doRand(0, carte->y);
}
while(!carteInside->carte[x][y].libre);
this->id = i;
this->orientation = doRand(0, 3);
this->longueur = doRand(2, 4);
this->vie = 2*(this->longueur)*(this->longueur);
carte->carte[this->x][this->y].libre = false;
carte->carte[this->x][this->y].batiment = this;
}
问题是您通过 Batiment
的构造函数填充 Carte
,但使用了一个被破坏的临时对象,使指针无效:
为什么?
在此语句中,您创建了一个临时 Batiment
:
Batiment temp(&carte, i);
您的构造函数显然会在 Carte::carte[][]
中插入指向新创建对象的指针。
不幸的是,您在 for 循环的块中定义了这个临时值:
for(int i = 0; i < nbrBatiments; i++){ //Ajout des Batiments sur le vecteur
Batiment temp(&carte, i); // <=== L'instance n'existe que le temps d'une itération !!
...
}
所以在这个循环的每一次迭代中都会创建和销毁这个临时文件。所以你的指针一离开循环就失效了。
当您稍后引用它时,它是未定义的行为。它能找到任何有意义的值只是一种运气。
顺便说一下,当你在 vector 中推回 temp 时,将创建对象的副本(相同的值,但仍然是另一个地址)。
如何解决?
嗯,保持你最初设计的想法,有几个解决方案。
最简单的方法是在免费商店中创建您的 Batiment:
Batiment *temp = new Batiment (&carte, i);
唯一的一点就是某天某个地方需要删除该对象。所以要么你在 Carte 的析构函数中处理这个,要么你改变你的 vecotr 以保留一个指针,以便你以后可以删除所有这些对象。
更好的方法是使用 shared_ptr
,它会自行处理内存管理。