質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.59%

std::vector<> .erase()メソッドでデストラクタが呼ばれてる居るのにも関わらずメモリリークしてしまう原因が知りたい。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 735
退会済みユーザー

退会済みユーザー

提示コードのPlayerクラスのUpdate()関数部ですがif()文の攻撃コメント部ですが。ここでpush_backしてその下のfor文で全部削除してデストラクタのprintf()が表示されてしっかりと廃棄されているはずなのですがなぜメモリリークしてしまうのでしょうか?またコピーコンストラクタもしっかり定義されておりデストラクタもしっかりdelete mSprite;と書いて居るのですがなぜでしょうか?

場所はBullet クラスのnew している部分で片方をコメントアウトしてもリークするので両方が原因と思うのですがどうすればいいのでしょうか?

イメージ説明
環境 Windows 10 64 bit

#include "../../Header/Game/Player.hpp"

// コンストラクタ
Player::Player(class Game* g,const char* fileName ) : Actor_2D()
{
    Owner = g;    //Game クラス

    mSprite = new Sprite(Owner,fileName);    // スプライトクラス
    mInput = new Input_Key(Owner);            // キー入力クラス
    mSpeed = SPEED;                            // 移動速度
    mVector = glm::vec2(0,1);                // 方向                

    mKeyCode = Key_Code::Up;


    // RIGHT
    mSpriteNum.at(0).at(0).at(0).x = 0;
    mSpriteNum.at(0).at(0).at(0).y = 0;
    mSpriteNum.at(0).at(0).at(1).x = CELL - 1;
    mSpriteNum.at(0).at(0).at(1).y = CELL - 1;

    mSpriteNum.at(0).at(1).at(0).x = 0;
    mSpriteNum.at(0).at(1).at(0).y = CELL - 1;
    mSpriteNum.at(0).at(1).at(1).x = CELL - 1;
    mSpriteNum.at(0).at(1).at(1).y = CELL * 2 - 1;

    // DOWN
    mSpriteNum.at(1).at(0).at(0).x = CELL;
    mSpriteNum.at(1).at(0).at(0).y = 1;
    mSpriteNum.at(1).at(0).at(1).x = CELL * 2 - 1;
    mSpriteNum.at(1).at(0).at(1).y = CELL - 1;

    mSpriteNum.at(1).at(1).at(0).x = CELL - 0;
    mSpriteNum.at(1).at(1).at(0).y = CELL + 1;
    mSpriteNum.at(1).at(1).at(1).x = CELL * 2 - 1;
    mSpriteNum.at(1).at(1).at(1).y = CELL * 2 - 1;

    // UP
    mSpriteNum.at(2).at(0).at(0).x = CELL * 2 + 1;
    mSpriteNum.at(2).at(0).at(0).y = 1;
    mSpriteNum.at(2).at(0).at(1).x = CELL * 3;
    mSpriteNum.at(2).at(0).at(1).y = CELL - 1;

    mSpriteNum.at(2).at(1).at(0).x = CELL * 2 + 1;
    mSpriteNum.at(2).at(1).at(0).y = CELL + 1;
    mSpriteNum.at(2).at(1).at(1).x = CELL * 3 - 1;
    mSpriteNum.at(2).at(1).at(1).y = CELL * 2 - 1;

    //    LEFT
    mSpriteNum.at(3).at(0).at(0).x = CELL * 3 + 1;
    mSpriteNum.at(3).at(0).at(0).y = 1;
    mSpriteNum.at(3).at(0).at(1).x = CELL * 4;
    mSpriteNum.at(3).at(0).at(1).y = CELL - 1;

    mSpriteNum.at(3).at(1).at(0).x = CELL * 3 + 1;
    mSpriteNum.at(3).at(1).at(0).y = CELL + 1;
    mSpriteNum.at(3).at(1).at(1).x = CELL * 4 - 1;
    mSpriteNum.at(3).at(1).at(1).y = CELL * 2 - 1;

}

// 計算
void Player::Update()
{
    // キー入力
    mSpeed = SPEED;
    if (mInput->KeyDownHold(GLFW_KEY_LEFT) == true)
    {
        mVector.x = -1.0f;
        mVector.y = 0.0f;
        mKeyCode = Key_Code::Left;
    }
    else if (mInput->KeyDownHold(GLFW_KEY_RIGHT) == true)
    {
        mVector.x = 1.0f;
        mVector.y = 0.0f;
        mKeyCode = Key_Code::Right;

    }
    else if (mInput->KeyDownHold(GLFW_KEY_UP) == true)
    {
        mVector.x = 0.0f;
        mVector.y = 1.0f;
        mKeyCode = Key_Code::Up;

    }
    else if (mInput->KeyDownHold(GLFW_KEY_DOWN) == true)
    {
        mVector.x = 0.0f;
        mVector.y = -1.0f;
        mKeyCode = Key_Code::Down;

    }    
    else {
        mSpeed = 0;
    }

    // 攻撃
    if (mInput->KeyDownHold(GLFW_KEY_SPACE) == true)
    {
        bullet.push_back(Bullet(Owner, mPosition, mVector));
    }


    // 弾 更新
    for (std::vector<Bullet>::iterator itr = bullet.begin(); itr != bullet.end(); )
    {
        itr = bullet.erase(itr);
    }
    mPosition += mVector * mSpeed;    //実移動
}


// 描画
void Player::Draw()
{    
    mSprite->DrawGraph(mPosition, mSpriteNum.at((int)mKeyCode).at(1).at(0), mSpriteNum.at((int)mKeyCode).at(1).at(1));
}






// デストラクタ
Player::~Player()
{

}
#include "../../Header/Game/Bullet.hpp"
#include "../../Header/Sprite.hpp"



// コンストラクタ
Bullet::Bullet(class Game* g,glm::vec2 pos,glm::vec2 vec) : Actor_2D()
{
    Owner = g;    //Game クラス

    mPosition = pos;    //座標
    mVector = vec;        //方向
    speed = 10;            //速度

    mSprite = new Sprite(g,"Assets/Bullet.png");    // スプライトクラス
}

// 計算
void Bullet::Update()
{
    mPosition.x += mVector.x * speed;
    mPosition.y += mVector.y * speed;

//    printf("mPosition.x: %f\n", mPosition.x);
//    printf("mPosition.y: %f\n",mPosition.y);

}

// 描画
void Bullet::Draw()
{
    glm::vec2 size = mSprite->getSize();
    mSprite->DrawGraph(mPosition,glm::vec2(0,1),glm::vec2(size.x,size.y));
}


glm::vec2 Bullet::getPosition()
{
    return mPosition;
}




// コピーコンストラクタ
Bullet::Bullet(const Bullet &b)
{
    printf("Bullet コピーコンストラクタ\n");


    mPosition = b.mPosition;
    mVector = b.mVector;
    speed = b.speed;
    Owner = b.Owner;

    mSprite = new Sprite(b.Owner, "Assets/Bullet.png");
    //mSprite = b.mSprite;
}


// デストラクタ
Bullet::~Bullet()
{
    printf("Bullet デストラクタ\n");
         delete mSprite;
    //printf("アドレス: %x\n",mSprite);
    mSprite = nullptr;
}
#include "../Header/Sprite.hpp"
#include "../Header/Shader.hpp"
#include "../Header/Game.hpp"
#include "../Header/Texture.hpp"
#include "../Header/VertexData.hpp"

// 数学ライブラリ
#include "glm/ext.hpp"
#include "glm/glm.hpp"

// OpenCV 
#include <opencv2/core.hpp>

class Game;
/*################################################################################################################
* 画像 描画クラス
################################################################################################################*/

//コンストラクタ
/*
* Game クラス
* テクスチャ パス
* 描画する画像の寸法
*/
Sprite::Sprite(class Game* g, const char* FileName) : Transform_2D(g)
{
    shader = new Shader(g,"Shader/2D/Sprite.vert", "Shader/2D/Sprite.frag");
    Owner = g;//Gameクラス

    Transform_2D::setTransfrom(glm::vec2(1,1),0,glm::vec2(0,0));    //トランスフォームを初期化

    //テクスチャを設定     
    glGenTextures(1, &TextureID);
    glBindTexture(GL_TEXTURE_2D, TextureID);

    float width = 0, height = 0;    //画像の寸法
    int channels = 0;                //画像のチャンネル数

    byte* data = LoadTexture(FileName,width,height,channels);    //テクスチャを取得


    mPicSize.x = width;
    mPicSize.y = height;

    //printf("widht: %f\n", width);
    //printf("height: %f\n", height);

    if (data != NULL) 
    {
        if (channels == 3)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)width, (GLsizei)height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        }
        else if (channels == 4)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        }
    }
    else {
        std::cerr << "Unable to load texture: " << FileName << std::endl;
    }



//    mSize = end - start;    //画像のサイズを取得

//    printf("width: %.2f\n", mSize.x);
//    printf("height: %.2f\n",mSize.y);

    /*
    vertex[0] = VertexAttribute_2D{ -width / 2.0f,height / 2.0f,    0,0 };
    vertex[1] = VertexAttribute_2D{ -width / 2.0f,-height / 2.0f,    0,1 };
    vertex[2] = VertexAttribute_2D{ width / 2.0f,-height / 2.0f,    1,1 };

    vertex[3] = VertexAttribute_2D{ -width / 2.0f,height / 2.0f,    0,0 };
    vertex[4] = VertexAttribute_2D{ width / 2.0f,-height / 2.0f,    1,1 };
    vertex[5] = VertexAttribute_2D{ width / 2.0f,height / 2.0f,    1,0 };
    */


    /*
    * 
    // 頂点情報を設定
    vertex[0] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,    start.x * uvWidth,start.y * uvHeight };
    vertex[1] = VertexAttribute_2D{ -mSize.x / 2.0f,-mSize.y / 2.0f,    start.x * uvWidth,end.y * uvHeight };
    vertex[2] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,    end.x * uvWidth,end.y * uvHeight };

    vertex[3] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,    start.x * uvWidth,start.y * uvHeight };
    vertex[4] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,    end.x * uvWidth,end.y * uvHeight };
    vertex[5] = VertexAttribute_2D{ mSize.x / 2.0f,mSize.y / 2.0f,        end.x * uvWidth,start.y * uvHeight };

    */


    //VAO


    //ミニマップを設定
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);

    //異方性フィルタリングを設定
    GLfloat largest;
    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest);




    delete data;
    data = nullptr;
}

//描画
void Sprite::DrawGraph(glm::vec2 pos, glm::vec2 start, glm::vec2 end)
{


    Transform_2D::UpdateTransform();        //トランスフォームを更新
    Transform_2D::setTransform_Move(pos);    //移動

    shader->Enable();    //シェーダーを有効にする
    shader->SetFloatUniform_3m("uViewMatrix", getViewMatrix());
    shader->SetFloatUniform_3m("uWorldMatrix", getWorldMatrix());


    glm::vec2 mSize;    
    mSize = end - start;    //画像のサイズを取得
//    printf("mSize.x  %f\n", mSize.x);
//`    printf("start.x. x%f\n", end.x);




    // 頂点情報を設定
    vertex[0] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,        start.x / mPicSize.x   ,start.y / mPicSize.y };

//    printf("%f\n", start.y / mSize.y);

    vertex[1] = VertexAttribute_2D{ -mSize.x / 2.0f,-mSize.y / 2.0f,    start.x / mPicSize.x   ,end.y / mPicSize.y };
    vertex[2] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,        end.x / mPicSize.x     ,end.y / mPicSize.y };

    vertex[3] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f,        start.x / mPicSize.x  ,start.y / mPicSize.y };
    vertex[4] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f,        end.x / mPicSize.x    ,end.y / mPicSize.y };
    vertex[5] = VertexAttribute_2D{ mSize.x / 2.0f,mSize.y / 2.0f,        end.x / mPicSize.x    ,start.y / mPicSize.y };



    //VAO
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    //VBO
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, (sizeof(vertex) / sizeof(vertex[0])) * sizeof(VertexAttribute_2D), vertex, GL_STATIC_DRAW);

    //頂点座標
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttribute_2D), NULL);

    //UV座標
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttribute_2D), (void*)(sizeof(float) * 2));


    glBindVertexArray(VAO);
    glBindTexture(GL_TEXTURE_2D, TextureID);
    glDrawArrays(GL_TRIANGLES, 0, (GLsizei)std::size(vertex));    

    // バッファを解放
    glDeleteBuffers(1,&VAO);
    glDeleteVertexArrays(1,&VAO);

    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);

}


// 画像サイズを取得
glm::vec2 Sprite::getSize()
{
    return mPicSize;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2021/01/27 17:41

    Sprite クラスを追加

    キャンセル

  • int32_t

    2021/01/27 17:45

    Spriteのクラス宣言全体とデストラクタの定義も掲載してください。

    キャンセル

  • 退会済みユーザー

    2021/01/28 01:34

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

回答 3

checkベストアンサー

+1

VCの場合、単純なメモリリークなら下記で検出可能です。
CRT ライブラリを使用したメモリ リークの検出
また、_CrtSetDbgFlag、_CrtDumpMemoryLeaks でググると、それっぽい記事がヒットするので探してみてください。
しかし、外部ライブラリの解放関数呼び出し漏れなどは検出出来ないので、関数の呼び出しログを取るなりして細かく調べていくしかないでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/01/27 17:36

    deleteが呼ばれているのであれば、delete対象のクラスのデストラクタの解放処理が不完全なのでしょう。
    同じように順次辿って地道に調べていくしかないです。

    キャンセル

  • 2021/01/27 17:42

    Sprite クラスを追加しましたが事前に確認してありますw一体どうなっているのでしょうか

    キャンセル

  • 2021/01/27 18:50

    Spriteクラスのデストラクタに
    // デストラクタ
    Sprite::~Sprite()
    {
    delete shader;
    shader = nullptr;
    glDeleteTextures(1,&TextureID);

    }としたらメモリリークが収まりました

    キャンセル

+1

Bullet::Bullet(const Bullet &b)で、class Game* gを初期化していないように見えます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/01/27 14:11 編集

    いえ直しましたがエラーが出ます。

    Bullet::Bullet(const Bullet &b)
    {
    printf("Bullet コピーコンストラクタ\n");


    mPosition = b.mPosition;
    mVector = b.mVector;
    speed = b.speed;
    Owner = b.Owner;

    mSprite = new Sprite(b.Owner, "Assets/Bullet.png");
    //mSprite = b.mSprite;
    }

    キャンセル

  • 2021/01/27 14:19

    どこで/どんなエラー?

    キャンセル

  • 2021/01/27 14:20 編集

    右に移動してスペースキーを連打するとメモリリークしながらメモリリークが発生します。

    キャンセル

+1

Bullet::Bullet(const Bullet &b) 内の

mSprite = new Sprite(Owner,"Assets/Bullet.png");

で使われている Owner の値がどうなってるのか謎ですが,大丈夫なのですか?
その結果としてここで作られた Sprite の破棄のタイミングにて問題が起きる ということだったりしませんか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/01/27 14:12

    (投稿エラーに手間取っている間に かぶってしまった…)

    キャンセル

  • 2021/01/27 14:14

    直したのですがだめだした。Bullet クラスのデストラクタでエラーが出ます。アクセスエラーです。
    カチカチスペースボタンを押して連射してると発生します。また メモリリークしてます。

    キャンセル

  • 2021/01/27 17:00

    とりあえずコピーコンストラクタだけでなく operator= の側も書いてみる(あるいは使用不能にする)べき.
    (どこかでコンストラクト以降にコピーが発生していれば,コピーコンストラクタで潰した問題と同じことが起きる)

    Spriteさえdeleteすれば何もかもうまくいくような話なのか?
    Sprite自身は真っ当な開放処理をできているのか?
    Spriteが保有している何かがあるのならば,その何かもまた,真っ当な開放処理をできているのか?
    その何かがさらに何かを保持しているならば……(以下,延々とつづく)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • トップ
  • C++に関する質問
  • std::vector<> .erase()メソッドでデストラクタが呼ばれてる居るのにも関わらずメモリリークしてしまう原因が知りたい。