📄 GameParticleSystem.cpp
#include <iostream>
#include <vector>
#include <memory>
#include <string>
struct Enemy {
int id;
int hp;
float x, y;
Enemy(int _id, float _x, float _y) : id(_id), hp(100), x(_x), y(_y) {}
~Enemy() {
std::cout << "[Destructor] Enemy " << id << " destroyed!\n";
}
};
struct Particle {
float vx, vy;
int life;
const Enemy* sourceEnemy; // ⚠️ 危険:敵への生ポインタ(所有権なし)
Particle(float _vx, float _vy, const Enemy* src)
: vx(_vx), vy(_vy), life(3), sourceEnemy(src) {}
void update() {
// 敵の最新座標に追従してエフェクトを出す処理
if (sourceEnemy) {
// ⚠️ ここで死んだ Enemy のメモリを読み出す!
std::cout << "Particle tracking Enemy at ("
<< sourceEnemy->x << ", " << sourceEnemy->y << ")\n";
}
life--;
}
};
class GameScene {
private:
std::vector<std::unique_ptr<Enemy>> m_enemies;
std::vector<Particle> m_particles;
public:
void init() {
m_enemies.push_back(std::make_unique<Enemy>(1, 100.0f, 200.0f));
// パーティクル生成:敵の生ポインタを渡す
m_particles.emplace_back(1.0f, 1.0f, m_enemies[0].get());
}
void updateFrame() {
std::cout << "--- Frame Start ---\n";
// 1. 敵が倒されてリストから消去(ここで Enemy が delete される!)
std::cout << "Action: 敵を撃破して消去します\n";
m_enemies.clear(); // ⚠️ メモリ解放!
// 2. パーティクルの更新処理(既に死んだ Enemy を見に行く!)
std::cout << "Action: 残留パーティクルを更新します\n";
for (auto& p : m_particles) {
p.update(); // 💥 Use-After-Free 発生!
}
std::cout << "--- Frame End ---\n";
}
};
int main() {
GameScene scene;
scene.init();
scene.updateFrame();
return 0;
}