Russian Qt Forum

Qt => Общие вопросы => Тема начата: 8Observer8 от Январь 12, 2015, 23:11



Название: Игра Танки. Segmentation error
Отправлено: 8Observer8 от Январь 12, 2015, 23:11
Привет

Не могу понять почему происходит ошибка. Запустите, пожалуйста, программу и нажмите "пробел": https://github.com/8Observer8/Tanks

Код
C++ (Qt)
void ExplosionOfProjectile::genTextures()
{
   QImage image( ":/Texture/TankSpriteSheet.png" );
   image = image.mirrored( false, true );
 
   QImage frame;
 
   frame = image.copy( 257, 112, 15, 15 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 272, 112, 16, 16 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 287, 111, 18, 18 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
}


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 12, 2015, 23:32
Ошибка происходит на строке из кода выше:

Код
C++ (Qt)
m_textures.push_back( new QOpenGLTexture( frame ) );


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 10:34
Там такая ситуация: когда я нажимаю на пробел, выполняется секция case Qt::Key_Space в этой функции:

Код
C++ (Qt)
void Scene::keyPressEvent( QKeyEvent *event )

Запускается таймер m_projectileTimer.start( 20 );

Каждые 20 милисекунд вызывается функция: void Scene::slotOfMovingOfProjectiles()

Крэш происходит когда сняряд подлетает к стенке и должен взорваться. Это происходит, когда Y-координата снаряда меньше или равна нулю. Тогда вызывается функция: addProjectileExplosion( x0, y0 ); которой передаётся положение снаряда. Эта функция должна показать анимацию взрыва:

Код
C++ (Qt)
void Scene::addProjectileExplosion( float x0, float y0 )
{
   ExplosionOfProjectile *explosion = new ExplosionOfProjectile( &m_program, m_vertexAttr, m_textureAttr, m_textureUniform );
   explosion->setX0( x0 );
   explosion->setY0( y0 );
   connect( explosion, SIGNAL( signalShowProjectileExplosion( int, bool ) ),
            this, SLOT( slotShowProjectileExplosion( int, bool ) ) );
   m_projectileExplosions[explosion->id()] = explosion;
   explosion->start();
 
   update();
}

Ошибка происходит при создании объекта:  "ExplosionOfTank *explosion = new"

Точнее, на строке m_textures.push_back

Код
C++ (Qt)
void ExplosionOfProjectile::genTextures()
{
   QImage image( ":/Texture/TankSpriteSheet.png" );
   image = image.mirrored( false, true );
 
   QImage frame;
 
   frame = image.copy( 257, 112, 15, 15 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 272, 112, 16, 16 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 287, 111, 18, 18 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
}

Не могу понять в чём ошибка. Почему "segmentation error"?


Название: Re: Segmentation error
Отправлено: Igors от Январь 13, 2015, 10:54
Для начала перед строкой вылета вставить
Код
C++ (Qt)
qDebug() << image << frame;

Потом открыть букварь и прочитать
Цитировать
This does create the underlying OpenGL texture object. Therefore, construction using this constructor does require a valid current OpenGL context.
И убедиться что контекст создан и установлен.


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 11:06
Добавил и получил:
Цитировать
QImage(null) QImage(null)

Сначала обрадовался, так как у видел, что пропустил букву "s" в слове Texture, исправил:

Код
C++ (Qt)
QImage image( ":/Textures/TankSpriteSheet.png" );

Теперь выводится:

Код
C++ (Qt)
QImage(QSize(400, 256),format=5,depth=32,devicePixelRatio=1,bytesPerLine=1600,byteCount=409600) QImage(QSize(15, 15),format=5,depth=32,devicePixelRatio=1,bytesPerLine=60,byteCount=900)

Самое обидное, что крэш так и истался на:

Код
C++ (Qt)
m_textures.push_back( new QOpenGLTexture( frame ) );


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 11:08
Потом открыть букварь и прочитать
Цитировать
This does create the underlying OpenGL texture object. Therefore, construction using this constructor does require a valid current OpenGL context.
И убедиться что контекст создан и установлен.

Вот это самое непонятное. Дело в том, что танк создаётся абсолютно также, как снаряд. Никакой разницы между классами. С танком прокатывает, а со снарядом нет. Так не должно быть


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 11:16
Единственная разница - объект класса Tank создаётся в initializeGL(), а объект класса ExplosionOfProjectile в слоте


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 11:19
Я добавил makeCurrent()\doneCurrent(), но всё равно не помогло:

Код
C++ (Qt)
void Scene::addProjectileExplosion( float x0, float y0 )
{
   makeCurrent();
   ExplosionOfProjectile *explosion = new ExplosionOfProjectile( &m_program, m_vertexAttr, m_textureAttr, m_textureUniform );
   explosion->setX0( x0 );
   explosion->setY0( y0 );
   connect( explosion, SIGNAL( signalShowProjectileExplosion( int, bool ) ),
            this, SLOT( slotShowProjectileExplosion( int, bool ) ) );
   m_projectileExplosions[explosion->id()] = explosion;
   explosion->start();
   doneCurrent();
 
   update();
}


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 11:32
Как передать контекст?


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 12:09
Ошибка не при создании объекта. Я ставлю точку останова на update() и программа останавливается, но потом если продолжить, то происходит крэш:

Код
C++ (Qt)
void Scene::addProjectileExplosion( float x0, float y0 )
{
   ExplosionOfProjectile *explosion = new ExplosionOfProjectile( &m_program, m_vertexAttr, m_textureAttr, m_textureUniform );
   explosion->setX0( x0 );
   explosion->setY0( y0 );
   connect( explosion, SIGNAL( signalShowProjectileExplosion( int, bool ) ),
            this, SLOT( slotShowProjectileExplosion( int, bool ) ) );
   m_projectileExplosions[explosion->id()] = explosion;
   explosion->start();
 
   update();
}


Название: Re: Segmentation error
Отправлено: Igors от Январь 13, 2015, 12:15
Выложите проект zip'ом, если соберется (Вындоуз, GL 3.3) - посмотрю


Название: Re: Segmentation error
Отправлено: m_ax от Январь 13, 2015, 12:17
Не, ну вы же пишите статьи по "современным контейнерам", а тут недоумеваете:

Код
C++ (Qt)
   std::vector<QOpenGLTexture*> m_textures;
   ...
   frame = image.copy( 257, 112, 15, 15 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 272, 112, 16, 16 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 287, 111, 18, 18 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 

  


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 12:18
Выложите проект zip'ом, если соберется (Вындоуз, GL 3.3) - посмотрю
Вот здесь (https://github.com/8Observer8/Tanks) справа кнопка "Donwload ZIP"


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 12:19
Не, ну вы же пишите статьи по "современным контейнерам", а тут недоумеваете:

Код
C++ (Qt)
   std::vector<QOpenGLTexture*> m_textures;
   ...
   frame = image.copy( 257, 112, 15, 15 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 272, 112, 16, 16 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 287, 111, 18, 18 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 

Здесь всё нормально теперь. Там проблема была - ошибка в пути. Теперь этот момент проходит. Я выше написал


Название: Re: Segmentation error
Отправлено: m_ax от Январь 13, 2015, 12:20
Цитировать
Здесь всё нормально теперь. Там проблема была - ошибка в пути. Теперь этот момент проходит. Я выше написал
Эх.. Ничего вы не поняли(


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 12:24
Цитировать
Здесь всё нормально теперь. Там проблема была - ошибка в пути. Теперь этот момент проходит. Я выше написал
Эх.. Ничего вы не поняли(
Не понял


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 13:52
Не, ну вы же пишите статьи по "современным контейнерам", а тут недоумеваете:

Код
C++ (Qt)
   std::vector<QOpenGLTexture*> m_textures;
   ...
   frame = image.copy( 257, 112, 15, 15 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 272, 112, 16, 16 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
   frame = image.copy( 287, 111, 18, 18 );
   m_textures.push_back( new QOpenGLTexture( frame ) );
 
Подскажите, пожалуйста, что тут не так?


Название: Re: Segmentation error
Отправлено: Igors от Январь 13, 2015, 14:02
На Вындоуз не пошло (нужен 5.4), а на Mac у меня вылет в др месте. Была такая конструкция  
Код
C++ (Qt)
   for ( auto iterOfProjectile = m_projectiles.begin(); iterOfProjectile != m_projectiles.end(); ++iterOfProjectile )
   {
                   ....
                   m_projectiles.erase( iterOfProjectile );
                   addProjectileExplosion( x0, y0 );
 
Если erase, то итератор становится невалидным, напр ++ с ним уже нельзя. Как с auto - не читал, но наверное тоже, т.к. здесь вылетала. Я сделал по-старинке (измененный файл в аттаче), вылета нет

Код
C++ (Qt)
typedef std::map<int, Projectile*> TMap;
TMap::iterator iterOfProjectile = m_projectiles.begin();
 
//    for ( auto iterOfProjectile = m_projectiles.begin(); iterOfProjectile != m_projectiles.end(); ++iterOfProjectile )
   while (iterOfProjectile != m_projectiles.end())
   {
       Projectile *projectile = iterOfProjectile->second;
 
       float x0 = projectile->x0();
       float y0 = projectile->y0();
 
bool doDel = false;
 
       switch ( projectile->direction() ) {
           case Projectile::Up:
               projectile->setY0( projectile->y0() - step );
               doDel = projectile->y0() <= 0.0f;
               break;
           case Projectile::Left:
               projectile->setX0( projectile->x0() - step );
               doDel = projectile->x0() < 0.0f;
               break;
           case Projectile::Down:
               projectile->setY0( projectile->y0() + step );
               doDel = projectile->y0() >= ( m_canvasHeight - projectile->height() );
               break;
           case Projectile::Right:
               projectile->setX0( projectile->x0() + step );
               doDel = projectile->x0() > ( m_canvasWidth - projectile->width() );
               break;
       }
 
if (doDel )
{
delete projectile;
m_projectiles.erase( iterOfProjectile++ );
addProjectileExplosion( x0, y0 );
}
else
iterOfProjectile++;
   }
 
Кстати как то же с auto?


Название: Re: Segmentation error
Отправлено: m_ax от Январь 13, 2015, 14:26
Цитировать
Подскажите, пожалуйста, что тут не так?
Что по вашему происходит с вектором, когда вы делаете push_back ?


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 14:55
Если erase, то итератор становится невалидным, напр ++ с ним уже нельзя. Как с auto - не читал, но наверное тоже, т.к. здесь вылетала. Я сделал по-старинке (измененный файл в аттаче), вылета нет
Огромное спасибо! Второй день страдал. Это страшно, когда кажется, что уже никогда её не найдёшь. Я поделюсь кодом игры, когда закончу первый уровень и приведу код в порядок. Как вас отблагодарить? Может пару сотен кинуть на телефон или webmoney? Нормально? Напишите в личку. Не хочу оставаться в долгу. Вы даже не представляете, как вы меня сильно выручили

Кстати, можно написать:

Код
C++ (Qt)
auto iterOfProjectile = m_projectiles.begin();

Вместо:

Код
C++ (Qt)
typedef std::map<int, Projectile*> TMap;
TMap::iterator iterOfProjectile = m_projectiles.begin();
 

Цитировать
Подскажите, пожалуйста, что тут не так?
Что по вашему происходит с вектором, когда вы делаете push_back ?
Зачем говорить загадками? Увеличится размер контейнера. Я не знаю, как внутренее реализован std::vector и сколько памяти он освободит. У меня есть предположение, что первый push_back самый затратный, он выделяет с запасом, чтобы какое-то количество push_back'ов были без выделения, а просто копирование на уже выделенную память. Что-то подобное я читал про QString из раздела "Container Classes" Уверен, что в моей игре, что push_back, что resize(), что обычный массив - погоды не делают


Название: Re: Segmentation error
Отправлено: Igors от Январь 13, 2015, 15:09
Что по вашему происходит с вектором, когда вы делаете push_back ?
Что-то слишком тонкие намеки :) Ну да, перераспределит память, но хранятся-то указатели, поэтому здесь это ничем не чревато.

Как вас отблагодарить?
Не писать поверхностных, непродуманных статей  :)

И кстати: если addProjectileExplosion( x0, y0 ) добавляет в мапу (не вижу но в принципе возможно), то вылета не будет, но не все эл-ты будут проитерированы (некоторые новые могут быть пропущены) 


Название: Re: Segmentation error
Отправлено: 8Observer8 от Январь 13, 2015, 18:29
И кстати: если addProjectileExplosion( x0, y0 ) добавляет в мапу (не вижу но в принципе возможно), то вылета не будет, но не все эл-ты будут проитерированы (некоторые новые могут быть пропущены)  

Я пока не понял, почему могут быть пропущены

Вот здесь (http://www.qtcentre.org/threads/61325-Segmentation-error?p=271383#post271383) ответили что:
Цитировать
Correct would be to use the return value of erase() as the new iterOfProjectile.

Подумаю над этим на досуге

Добавлю пока стенок и сделаю, чтобы можно было взорвать второй танк

Ещё у меня проблемы со звуком. Я хотел сделать отдельный класс SoundOfShot наследником QRunnable и в переопределённом методе run() запускать звуковой эффект выстрела (m_sound это объект класса QSoundEffect):
Код
C++ (Qt)
void SoundOfShot::run()
{
   m_sound.play();
   while ( m_sound.isPlaying() );
}

Объект класса SoundOfShot хотел создавать при нажатии на пробел:

Код
C++ (Qt)
SoundOfShot *sound = new SoundOfShot;
sound->setAutoDelete( true );
QThreadPool::globalInstance()->start( sound );

А перед этим в конструкторе:

Код
C++ (Qt)
QThreadPool::globalInstance()->setMaxThreadCount( 15 );

Идея со звуком и потоками правильная?


Название: Re: Segmentation error
Отправлено: Igors от Январь 14, 2015, 08:50
Вот здесь (http://www.qtcentre.org/threads/61325-Segmentation-error?p=271383#post271383) ответили что:
Цитировать
Correct would be to use the return value of erase() as the new iterOfProjectile.
Это предполагает QMap (а там std::map). Впрочем и с QMap цикл for не годится

Ещё у меня проблемы со звуком. Я хотел сделать отдельный класс SoundOfShot наследником QRunnable и в переопределённом методе run() запускать звуковой эффект выстрела (m_sound это объект класса QSoundEffect):
Код
C++ (Qt)
void SoundOfShot::run()
{
   m_sound.play();
   while ( m_sound.isPlaying() );
}
...
Идея со звуком и потоками правильная?
Ну такой run точно неверный, не может класс быть сделан так глупо что его надо так ждать. Что произойдет если, не мудрствуя лукаво, просто вызвать play в главной нитке? Может он асинхронный, и проблемы никакой нет. Для начала проверьте