🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

1611閲覧

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

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/01/27 04:24

編集2021/01/27 08:41

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

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

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

cpp

1#include "../../Header/Game/Player.hpp" 2 3// コンストラクタ 4Player::Player(class Game* g,const char* fileName ) : Actor_2D() 5{ 6 Owner = g; //Game クラス 7 8 mSprite = new Sprite(Owner,fileName); // スプライトクラス 9 mInput = new Input_Key(Owner); // キー入力クラス 10 mSpeed = SPEED; // 移動速度 11 mVector = glm::vec2(0,1); // 方向 12 13 mKeyCode = Key_Code::Up; 14 15 16 // RIGHT 17 mSpriteNum.at(0).at(0).at(0).x = 0; 18 mSpriteNum.at(0).at(0).at(0).y = 0; 19 mSpriteNum.at(0).at(0).at(1).x = CELL - 1; 20 mSpriteNum.at(0).at(0).at(1).y = CELL - 1; 21 22 mSpriteNum.at(0).at(1).at(0).x = 0; 23 mSpriteNum.at(0).at(1).at(0).y = CELL - 1; 24 mSpriteNum.at(0).at(1).at(1).x = CELL - 1; 25 mSpriteNum.at(0).at(1).at(1).y = CELL * 2 - 1; 26 27 // DOWN 28 mSpriteNum.at(1).at(0).at(0).x = CELL; 29 mSpriteNum.at(1).at(0).at(0).y = 1; 30 mSpriteNum.at(1).at(0).at(1).x = CELL * 2 - 1; 31 mSpriteNum.at(1).at(0).at(1).y = CELL - 1; 32 33 mSpriteNum.at(1).at(1).at(0).x = CELL - 0; 34 mSpriteNum.at(1).at(1).at(0).y = CELL + 1; 35 mSpriteNum.at(1).at(1).at(1).x = CELL * 2 - 1; 36 mSpriteNum.at(1).at(1).at(1).y = CELL * 2 - 1; 37 38 // UP 39 mSpriteNum.at(2).at(0).at(0).x = CELL * 2 + 1; 40 mSpriteNum.at(2).at(0).at(0).y = 1; 41 mSpriteNum.at(2).at(0).at(1).x = CELL * 3; 42 mSpriteNum.at(2).at(0).at(1).y = CELL - 1; 43 44 mSpriteNum.at(2).at(1).at(0).x = CELL * 2 + 1; 45 mSpriteNum.at(2).at(1).at(0).y = CELL + 1; 46 mSpriteNum.at(2).at(1).at(1).x = CELL * 3 - 1; 47 mSpriteNum.at(2).at(1).at(1).y = CELL * 2 - 1; 48 49 // LEFT 50 mSpriteNum.at(3).at(0).at(0).x = CELL * 3 + 1; 51 mSpriteNum.at(3).at(0).at(0).y = 1; 52 mSpriteNum.at(3).at(0).at(1).x = CELL * 4; 53 mSpriteNum.at(3).at(0).at(1).y = CELL - 1; 54 55 mSpriteNum.at(3).at(1).at(0).x = CELL * 3 + 1; 56 mSpriteNum.at(3).at(1).at(0).y = CELL + 1; 57 mSpriteNum.at(3).at(1).at(1).x = CELL * 4 - 1; 58 mSpriteNum.at(3).at(1).at(1).y = CELL * 2 - 1; 59 60} 61 62// 計算 63void Player::Update() 64{ 65 // キー入力 66 mSpeed = SPEED; 67 if (mInput->KeyDownHold(GLFW_KEY_LEFT) == true) 68 { 69 mVector.x = -1.0f; 70 mVector.y = 0.0f; 71 mKeyCode = Key_Code::Left; 72 } 73 else if (mInput->KeyDownHold(GLFW_KEY_RIGHT) == true) 74 { 75 mVector.x = 1.0f; 76 mVector.y = 0.0f; 77 mKeyCode = Key_Code::Right; 78 79 } 80 else if (mInput->KeyDownHold(GLFW_KEY_UP) == true) 81 { 82 mVector.x = 0.0f; 83 mVector.y = 1.0f; 84 mKeyCode = Key_Code::Up; 85 86 } 87 else if (mInput->KeyDownHold(GLFW_KEY_DOWN) == true) 88 { 89 mVector.x = 0.0f; 90 mVector.y = -1.0f; 91 mKeyCode = Key_Code::Down; 92 93 } 94 else { 95 mSpeed = 0; 96 } 97 98 // 攻撃 99 if (mInput->KeyDownHold(GLFW_KEY_SPACE) == true) 100 { 101 bullet.push_back(Bullet(Owner, mPosition, mVector)); 102 } 103 104 105 // 弾 更新 106 for (std::vector<Bullet>::iterator itr = bullet.begin(); itr != bullet.end(); ) 107 { 108 itr = bullet.erase(itr); 109 } 110 mPosition += mVector * mSpeed; //実移動 111} 112 113 114// 描画 115void Player::Draw() 116{ 117 mSprite->DrawGraph(mPosition, mSpriteNum.at((int)mKeyCode).at(1).at(0), mSpriteNum.at((int)mKeyCode).at(1).at(1)); 118} 119 120 121 122 123 124 125// デストラクタ 126Player::~Player() 127{ 128 129} 130

cpp

1#include "../../Header/Game/Bullet.hpp" 2#include "../../Header/Sprite.hpp" 3 4 5 6// コンストラクタ 7Bullet::Bullet(class Game* g,glm::vec2 pos,glm::vec2 vec) : Actor_2D() 8{ 9 Owner = g; //Game クラス 10 11 mPosition = pos; //座標 12 mVector = vec; //方向 13 speed = 10; //速度 14 15 mSprite = new Sprite(g,"Assets/Bullet.png"); // スプライトクラス 16} 17 18// 計算 19void Bullet::Update() 20{ 21 mPosition.x += mVector.x * speed; 22 mPosition.y += mVector.y * speed; 23 24// printf("mPosition.x: %f\n", mPosition.x); 25// printf("mPosition.y: %f\n",mPosition.y); 26 27} 28 29// 描画 30void Bullet::Draw() 31{ 32 glm::vec2 size = mSprite->getSize(); 33 mSprite->DrawGraph(mPosition,glm::vec2(0,1),glm::vec2(size.x,size.y)); 34} 35 36 37glm::vec2 Bullet::getPosition() 38{ 39 return mPosition; 40} 41 42 43 44 45// コピーコンストラクタ 46Bullet::Bullet(const Bullet &b) 47{ 48 printf("Bullet コピーコンストラクタ\n"); 49 50 51 mPosition = b.mPosition; 52 mVector = b.mVector; 53 speed = b.speed; 54 Owner = b.Owner; 55 56 mSprite = new Sprite(b.Owner, "Assets/Bullet.png"); 57 //mSprite = b.mSprite; 58} 59 60 61// デストラクタ 62Bullet::~Bullet() 63{ 64 printf("Bullet デストラクタ\n"); 65 delete mSprite; 66 //printf("アドレス: %x\n",mSprite); 67 mSprite = nullptr; 68} 69

cpp

1#include "../Header/Sprite.hpp" 2#include "../Header/Shader.hpp" 3#include "../Header/Game.hpp" 4#include "../Header/Texture.hpp" 5#include "../Header/VertexData.hpp" 6 7// 数学ライブラリ 8#include "glm/ext.hpp" 9#include "glm/glm.hpp" 10 11// OpenCV 12#include <opencv2/core.hpp> 13 14class Game; 15/*################################################################################################################ 16* 画像 描画クラス 17################################################################################################################*/ 18 19//コンストラクタ 20/* 21* Game クラス 22* テクスチャ パス 23* 描画する画像の寸法 24*/ 25Sprite::Sprite(class Game* g, const char* FileName) : Transform_2D(g) 26{ 27 shader = new Shader(g,"Shader/2D/Sprite.vert", "Shader/2D/Sprite.frag"); 28 Owner = g;//Gameクラス 29 30 Transform_2D::setTransfrom(glm::vec2(1,1),0,glm::vec2(0,0)); //トランスフォームを初期化 31 32 //テクスチャを設定 33 glGenTextures(1, &TextureID); 34 glBindTexture(GL_TEXTURE_2D, TextureID); 35 36 float width = 0, height = 0; //画像の寸法 37 int channels = 0; //画像のチャンネル数 38 39 byte* data = LoadTexture(FileName,width,height,channels); //テクスチャを取得 40 41 42 mPicSize.x = width; 43 mPicSize.y = height; 44 45 //printf("widht: %f\n", width); 46 //printf("height: %f\n", height); 47 48 if (data != NULL) 49 { 50 if (channels == 3) 51 { 52 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)width, (GLsizei)height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 53 } 54 else if (channels == 4) 55 { 56 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 57 } 58 } 59 else { 60 std::cerr << "Unable to load texture: " << FileName << std::endl; 61 } 62 63 64 65// mSize = end - start; //画像のサイズを取得 66 67// printf("width: %.2f\n", mSize.x); 68// printf("height: %.2f\n",mSize.y); 69 70 /* 71 vertex[0] = VertexAttribute_2D{ -width / 2.0f,height / 2.0f, 0,0 }; 72 vertex[1] = VertexAttribute_2D{ -width / 2.0f,-height / 2.0f, 0,1 }; 73 vertex[2] = VertexAttribute_2D{ width / 2.0f,-height / 2.0f, 1,1 }; 74 75 vertex[3] = VertexAttribute_2D{ -width / 2.0f,height / 2.0f, 0,0 }; 76 vertex[4] = VertexAttribute_2D{ width / 2.0f,-height / 2.0f, 1,1 }; 77 vertex[5] = VertexAttribute_2D{ width / 2.0f,height / 2.0f, 1,0 }; 78 */ 79 80 81 /* 82 * 83 // 頂点情報を設定 84 vertex[0] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f, start.x * uvWidth,start.y * uvHeight }; 85 vertex[1] = VertexAttribute_2D{ -mSize.x / 2.0f,-mSize.y / 2.0f, start.x * uvWidth,end.y * uvHeight }; 86 vertex[2] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f, end.x * uvWidth,end.y * uvHeight }; 87 88 vertex[3] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f, start.x * uvWidth,start.y * uvHeight }; 89 vertex[4] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f, end.x * uvWidth,end.y * uvHeight }; 90 vertex[5] = VertexAttribute_2D{ mSize.x / 2.0f,mSize.y / 2.0f, end.x * uvWidth,start.y * uvHeight }; 91 92 */ 93 94 95 //VAO 96 97 98 //ミニマップを設定 99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 101 glGenerateMipmap(GL_TEXTURE_2D); 102 103 //異方性フィルタリングを設定 104 GLfloat largest; 105 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest); 106 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest); 107 108 109 110 111 delete data; 112 data = nullptr; 113} 114 115//描画 116void Sprite::DrawGraph(glm::vec2 pos, glm::vec2 start, glm::vec2 end) 117{ 118 119 120 Transform_2D::UpdateTransform(); //トランスフォームを更新 121 Transform_2D::setTransform_Move(pos); //移動 122 123 shader->Enable(); //シェーダーを有効にする 124 shader->SetFloatUniform_3m("uViewMatrix", getViewMatrix()); 125 shader->SetFloatUniform_3m("uWorldMatrix", getWorldMatrix()); 126 127 128 glm::vec2 mSize; 129 mSize = end - start; //画像のサイズを取得 130// printf("mSize.x %f\n", mSize.x); 131//` printf("start.x. x%f\n", end.x); 132 133 134 135 136 // 頂点情報を設定 137 vertex[0] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f, start.x / mPicSize.x ,start.y / mPicSize.y }; 138 139// printf("%f\n", start.y / mSize.y); 140 141 vertex[1] = VertexAttribute_2D{ -mSize.x / 2.0f,-mSize.y / 2.0f, start.x / mPicSize.x ,end.y / mPicSize.y }; 142 vertex[2] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f, end.x / mPicSize.x ,end.y / mPicSize.y }; 143 144 vertex[3] = VertexAttribute_2D{ -mSize.x / 2.0f,mSize.y / 2.0f, start.x / mPicSize.x ,start.y / mPicSize.y }; 145 vertex[4] = VertexAttribute_2D{ mSize.x / 2.0f,-mSize.y / 2.0f, end.x / mPicSize.x ,end.y / mPicSize.y }; 146 vertex[5] = VertexAttribute_2D{ mSize.x / 2.0f,mSize.y / 2.0f, end.x / mPicSize.x ,start.y / mPicSize.y }; 147 148 149 150 //VAO 151 glGenVertexArrays(1, &VAO); 152 glBindVertexArray(VAO); 153 154 //VBO 155 glGenBuffers(1, &VBO); 156 glBindBuffer(GL_ARRAY_BUFFER, VBO); 157 glBufferData(GL_ARRAY_BUFFER, (sizeof(vertex) / sizeof(vertex[0])) * sizeof(VertexAttribute_2D), vertex, GL_STATIC_DRAW); 158 159 //頂点座標 160 glEnableVertexAttribArray(0); 161 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttribute_2D), NULL); 162 163 //UV座標 164 glEnableVertexAttribArray(1); 165 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexAttribute_2D), (void*)(sizeof(float) * 2)); 166 167 168 glBindVertexArray(VAO); 169 glBindTexture(GL_TEXTURE_2D, TextureID); 170 glDrawArrays(GL_TRIANGLES, 0, (GLsizei)std::size(vertex)); 171 172 // バッファを解放 173 glDeleteBuffers(1,&VAO); 174 glDeleteVertexArrays(1,&VAO); 175 176 glBindVertexArray(0); 177 glBindTexture(GL_TEXTURE_2D, 0); 178 179} 180 181 182// 画像サイズを取得 183glm::vec2 Sprite::getSize() 184{ 185 return mPicSize; 186}

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/01/27 05:22

GitHub全文ソースを追加しました。
int32_t

2021/01/27 05:44 編集

アクセスエラーになるのはBulletをvectorに入れていることが原因で間違いないのですか? Bulletはそもそもコピー可能にしてよい概念ですか?
退会済みユーザー

退会済みユーザー

2021/01/27 05:50

bullet変数に代入していいのですがだめなのでしょうか?一つ一つprintf();しましたがどこが原因でどうなっているのか理解出来ませんw
t_obara

2021/01/27 06:30

結局mSpriteの破棄時にエラーなのですか?開発環境も提示されていないので、スペースカチカチで何をしているか把握できる人はいないかと。
退会済みユーザー

退会済みユーザー

2021/01/27 06:41

文章と提示コードを修正しました。
int32_t

2021/01/27 07:04

あれ? アクセスエラーの問題はどうなったんでしょうか? メモリリークはどうやって確認して何のオブジェクトがリークしているのですか?
退会済みユーザー

退会済みユーザー

2021/01/27 07:08

std::vector<Bullet> bullet変数で起きてます。しっかり.erase()しているのにも関わらずメモリリークしている理由はんでしょうか?
退会済みユーザー

退会済みユーザー

2021/01/27 07:26 編集

他にも解放出来ていないからでしょう。
int32_t

2021/01/27 07:27

診断ツールを使えば、どこで確保されたメモリがリークしているかわかりますよね。それを開示してください。で、この質問の当初のアクセスエラーの問題は解決したのですか?
退会済みユーザー

退会済みユーザー

2021/01/27 07:31

いえ、メモリリークでアクセスエラーが起きてました。主原因がメモリリークだったのでこっちにしました。
退会済みユーザー

退会済みユーザー

2021/01/27 08:41

Sprite クラスを追加
int32_t

2021/01/27 08:45

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

回答3

0

ベストアンサー

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

投稿2021/01/27 07:34

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/01/27 07:37

質問ですがためしに提示コード内のnew を全てコメントアウトしてやったらメモリリークが収まったので この提示コード内でメモリリークしてるのは確定的なのですwどうしたらいいのでしょうか?。。。。
退会済みユーザー

退会済みユーザー

2021/01/27 07:57 編集

一つづつ対応するnew-deleteをコメント化を解除して、どれを解除した時にメモリリークするかをまずは特定しては。
退会済みユーザー

退会済みユーザー

2021/01/27 08:04

特定しました。しかしながら直し方がわかりません。
退会済みユーザー

退会済みユーザー

2021/01/27 08:19 編集

どこでリークしているかを質問文に追記してください。また、メモリリークしているnewに対応するdeleteは書かれていて、それは呼ばれているのでしょうか?
退会済みユーザー

退会済みユーザー

2021/01/27 08:23 編集

new の部分です。片方をコメントアウトして試しましたが両方でした。またdelete mSprite;のコード部で ブレークポイントが発生したりと全体的に挙動がおかしいです。
int32_t

2021/01/27 08:35

では Sprite クラスにバグがある可能性が高そうですね。そのコードは質問文にありませんけども。
退会済みユーザー

退会済みユーザー

2021/01/27 08:36

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

退会済みユーザー

2021/01/27 08:42

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

退会済みユーザー

2021/01/27 09:50

Spriteクラスのデストラクタに // デストラクタ Sprite::~Sprite() { delete shader; shader = nullptr; glDeleteTextures(1,&TextureID); }としたらメモリリークが収まりました
guest

0

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

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

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

投稿2021/01/27 05:11

fana

総合スコア11985

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/01/27 05:12

(投稿エラーに手間取っている間に かぶってしまった…)
退会済みユーザー

退会済みユーザー

2021/01/27 05:14

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

2021/01/27 08:00

とりあえずコピーコンストラクタだけでなく operator= の側も書いてみる(あるいは使用不能にする)べき. (どこかでコンストラクト以降にコピーが発生していれば,コピーコンストラクタで潰した問題と同じことが起きる) Spriteさえdeleteすれば何もかもうまくいくような話なのか? Sprite自身は真っ当な開放処理をできているのか? Spriteが保有している何かがあるのならば,その何かもまた,真っ当な開放処理をできているのか? その何かがさらに何かを保持しているならば……(以下,延々とつづく)
guest

0

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

投稿2021/01/27 05:08

maisumakun

総合スコア145970

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/01/27 05: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; }
episteme

2021/01/27 05:19

どこで/どんなエラー?
退会済みユーザー

退会済みユーザー

2021/01/27 07:18 編集

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問