我不明白多线程游戏中的对象不匹配

I don't understand the object mismatch in a multithreading game

本文关键字:对象 不匹配 游戏 明白 多线程      更新时间:2023-10-16

我正在开发一个多线程游戏。 它有3个类:

  • Carte,一张由几个Case组成的地图
  • Batiment,一艘船,船只互相争斗。
  • Case 是地图的基本单元格,可以与Batiment链接。

每个线程控制一个Batiment对象,一切似乎都很好,但是当我尝试输出游戏,显示代表地图中Batiment的不同线程的ID号时,它不起作用。 它不会打印每个线程,而是只打印我在main.cpp中创建的最后Batiment

我在上面停滞了 3 天...

这是我的文件:

主.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: %dn", rc); return EXIT_FAILURE;
        }
    }

Batiment.cpp:启动器函数,我用它来将对象传递给线程:

void *Batiment::launcher(void *context)
{
     return static_cast<Batiment*>(context)->jouer();
}

Batiment.h:这里是班级的成员

Carte *carteInside;
static void *launcher(void *context);
int id;
void *jouer();

Case.h:这里是类的成员,它链接到一个 Batiment 对象:

    Batiment *batiment;

我的Batiment::jouer()方法只是一种移动地图中当前对象并拍摄另一个对象的方法......当我"cout"调用jouer()对象的当前 id 时,所描述的问题发生在哪里

菜单.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:班级成员

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 !! 
        ...
    }

因此,这个临时在这个循环的每次迭代中都会被创建和销毁。因此,一旦您离开循环,您的指针就无效。

当你稍后提到它时,它是未定义的行为。它找到任何有意义的价值只是运气。

顺便说一下,当您在向量中回推 temp 时,将创建对象的副本(相同的值,但仍然是另一个地址)。

怎么解决?

好吧,保持您初始设计的想法,有几种解决方案。

最简单的方法是在免费商店中创建您的Batiment:

 Batiment *temp = new Batiment (&carte, i);  

唯一的一点是,有一天需要在某处删除该对象。 因此,要么在 Carte 的析构函数中处理此问题,要么更改 vecotr 以保留指针,以便以后可以删除所有这些对象。

更好的方法是使用shared_ptr,它们自己负责记忆管理。