在删除条目时,std ::指针列表变为无效

Sha*_*ley 1 c++ pointers segmentation-fault stdlist

我有一个指针列表,它们引用了需要转向我游戏的时间对象.此示例TimeObject*在列表中有两个.此代码有效,直到从列表中删除某个项目:当发生这种情况时,另一个项目指向无效的地址.TimeObject发生这种情况时都不会被删除; 只有指针从列表中删除.是什么造成的?

TimeUnlink()被称为TimeObject::Tick().它不是静态的,但列表是.

我在Linux上使用GCC 4.6.2.该程序没有线程.

void TimeObject::TimeUnlink()
{
    printf("Time unlink\n");

    TimeObject::list_.remove(this);

    timeobject_flags_.linked_ = 0;
}

void GameTime::GameTurn(uint16_t _time)
{
    tick_ += _time;

    for(std::list<TimeObject*>::iterator it = TimeObject::list_.begin(); it != TimeObject::list_.end(); ++it)
    {
        TimeObject *timeobject = *it;

        printf("GameTurn %p\n", timeobject);

        if(timeobject == NULL) { printf("continue\n"); continue; }

        timeobject->time_ += _time;

        if(timeobject->speed_ && timeobject->time_ >= timeobject->speed_)
        {
            while(timeobject->timeobject_flags_.linked_ && timeobject->time_ - timeobject->speed_ > 0)
            {
                timeobject->time_ -= timeobject->speed_;

                if(timeobject->mapobject_)
                {
                    timeobject->mapobject_->Tick();
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

错误输出:

GameTurn 0xc1e048
GameTurn 0x696828
GameTurn 0xc1e048
GameTurn 0x696828
GameTurn 0xc1e048
GameTurn 0x696828
GameTurn 0xc1e048
Time unlink
GameTurn (nil)
continue
GameTurn 0xc1e030

Program received signal SIGSEGV, Segmentation fault.
0x00000000004059a1 in GameTime::GameTurn(unsigned short) ()
Run Code Online (Sandbox Code Playgroud)

小智 5

在输出序列中,指针在0xc1e048和之间交替0x696828,这意味着它0xc1e048是列表中的第一项,0x696828是第二项.基于此,看起来对象at 在循环中间0xc1e048GameTurn::GameTurn被取消链接,很可能是在调用中timeobject->mapobject_->Tick(),或者由@hmjd提到的另一个线程.从列表中删除对象会使指向该对象的迭代器无效.

假设代码是单线程的,并且调用Tick导致问题,那么这样的事情可能会起作用:

void GameTime::GameTurn(uint16_t _time)
{
    tick_ += _time;

    for(std::list<TimeObject*>::iterator it = TimeObject::list_.begin(); it != TimeObject::list_.end(); )
    {
        TimeObject *timeobject = *it;
        ++it;

        printf("GameTurn %p\n", timeobject);

        if(timeobject == NULL) { printf("continue\n"); continue; }

        timeobject->time_ += _time;

        if(timeobject->speed_ && timeobject->time_ >= timeobject->speed_)
        {
            while(timeobject->timeobject_flags_.linked_ && timeobject->time_ - timeobject->speed_ > 0)
            {
                timeobject->time_ -= timeobject->speed_;

                if(timeobject->mapobject_)
                {
                    timeobject->mapobject_->Tick();
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(唯一的区别是在增量it从移动for分配后声明循环体ittimeobject.推进it,才能无效应该解决这个问题.

如果您的代码是多线程的,则需要一个互斥锁.