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

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

新規登録して質問してみよう
ただいま回答率
85.46%
C++

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

Q&A

解決済

2回答

3727閲覧

C/C++ 構造体メンバ変数をデストラクタでfreeしようとしたら怒られた

whitetree

総合スコア1

C++

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

0グッド

0クリップ

投稿2021/09/24 10:21

編集2021/09/24 11:05

言語はC++で、開発環境はVisualStudio2019です。

現在C++を用いて開発を行っていますが、タイトルに示したようにメモリの管理について、どうしても自分で解決ができないことがあり、質問させていただきました。なお、変数や構造体の命名は実際の実装とは変えています。

#問題のコード
ヘッダファイルに以下のように構造体を宣言しています。

C++

1//a.h 2struct hoge { 3 int dataCnt; 4 int** data; 5 hoge(int cnt) { 6 dataCnt = cnt; 7 data = (int**)malloc(sizeof(int*)*cnt); 8 for(int i = 0;i < cnt;i++){ 9 data[i] = (int*)malloc(sizeof(int)*3); 10 } 11 } 12 ~hoge() { 13 for(int i = 0;i < dataCnt;i++){ 14 free(data[i]); 15 } 16 free(data); 17 } 18}

この構造体をソースファイルで以下のように使用しています。

C++

1//a.cpp 2 /*-----省略-----*/ 3 for(int i = 0;i < MAX_LOOP_COUNT;i++) { 4 hoge moge(ARRAY_SIZE); 5 /*-----いろいろな処理-----*/ 6 } 7 /*-----省略-----*/

#発生している問題
構造体hogeのコンストラクタにてmallocで動的メモリ確保を行っているので、当然freeによるメモリ解放が必要と思いデストラクタに処理を書いたのですが、これをデバッグしてみると"読み取り中のアクセス違反"だと怒られてプログラムが停止してしまいます。

forループを抜けて構造体変数mogeの寿命が終わってメモリが解放されているのかな、とも思ったのですが、mallocで確保したメモリがfreeせずに解放されるという話を聞いたことないしなぁ(これは完全に私の知識不足かと思われます...)とか思いながら、どういうことなのかわからず途方に暮れています。
#お聞きしたいこと
どなたか、どうして構造体のデストラクタでfreeを行うとアクセス違反となってしまうのか教えていただけないでしょうか。
#とりあえず...
ひとまずアクセスできないメモリが存在し続けてしまうかもしれないというのはどうにも怖いので、ヘッダファイルとソースコードを以下のように修正して開発を続けています(この状態ではメモリアクセス違反は発生しませんでした)。

C++

1//a.h 2struct hoge { 3 int dataCnt; 4 int** data; 5 hoge(int cnt) { 6 dataCnt = cnt; 7 data = (int**)malloc(sizeof(int*)*cnt); 8 for(int i = 0;i < cnt;i++){ 9 data[i] = (int*)malloc(sizeof(int)*3); 10 } 11 } 12 ~hoge() { 13 /*デストラクタで開放するのをやめる*/ 14 } 15}

C++

1//a.cpp 2 /*-----省略-----*/ 3 for(int i = 0;i < MAX_LOOP_COUNT;i++) { 4 hoge moge(ARRAY_SIZE); 5 /*-----いろいろな処理-----*/ 6 7 /*処理が終わった後に、デストラクタが呼ばれる前に構造体メンバ変数のメモリ解放を行う*/ 8 for(int i = 0;i < moge.dataCnt;i++){ 9 free(moge.data[i]); 10 } 11 free(moge.data); 12 } 13 /*-----省略-----*/

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

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

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

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

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

jimbe

2021/09/24 10:37

c は関係無いようですので、ご質問のタグから外して頂けますか。
whitetree

2021/09/24 10:49

ややこしくて申し訳ありません。 使用言語自体はC++なのですが、free、malloc当たりの話はむしろC寄りなのかなと思ってCも含めたのですが、やはり外したほうが良いでしょうか?
jimbe

2021/09/24 15:29

malloc や free 自体の問題では無くそれらが使われるタイミング(?) というお話のようですので、そこに "デストラクタ" が出てくると C では対処できないということで。 余計な面倒をお掛けしてすみません。
whitetree

2021/09/24 15:31

こちらこそ、問題の本質を見誤って質問していました。 いま改めて考えたところ、確かにCをタグ付けするのは間違っていたかのように思います。ご指摘ありがとうございます!
guest

回答2

0

記載間違いの可能性もありますが、とりあえず下記の部分がおかしいかなと思います。

1.data = (int**)malloc(sizeof(int)*cnt);

sizeof(int) → sizeof(int*)

2.for(int i = 0;i < cnt;i++){

cnt → dataCnt

投稿2021/09/24 10:39

Serbonis

総合スコア581

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

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

whitetree

2021/09/24 10:44

申し訳ありません、完全に記載ミスです、すぐに修正します。
Serbonis

2021/09/24 10:48

編集後に dataCnt = cnt; が dataCnt; になってしまっているようです。
whitetree

2021/09/24 10:55

修正できたと思います。 しょうもないミスばっかりするので、今もちょっとチェック続けてます
guest

0

ベストアンサー

C++

1~hoge() { 2 for(int i = 0;i < cnt;i++){

このcntはどこから来ているのですか?

あと、これは別の問題ですが

C++

1 data = (int**)malloc(sizeof(int)*cnt);

sizeof(int*)*cntであるべきなのでは?

投稿2021/09/24 10:34

itagagaki

総合スコア8402

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

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

whitetree

2021/09/24 10:44

すいません、完全にミスってました。 cntは公司詫田引数のcntをdataCntに代入するので、dataCntの間違いですね... cnt自体は基本的に3~10程度の値をとります。 質問に間違いだらけで大変申し訳ありません、すぐに修正します。
itagagaki

2021/09/24 10:47

修正したコードでもう一度ちゃんとビルドして実行してみました?
whitetree

2021/09/24 10:50

はい、やはり同様にアクセス違反が発生してしまいます。
itagagaki

2021/09/24 10:55

コードをコピペしてビルド、実行してみましたが、問題ありません。 (struct {} に ; が付いていないのは付けて moge の呼び出しは hoge に直しました) どこか別のところに問題があるのでは? #include <stdlib.h> #include <stdio.h> #define MAX_LOOP_COUNT 10 #define ARRAY_SIZE 10 struct hoge { int dataCnt; int** data; hoge(int cnt) { dataCnt = cnt; data = (int**)malloc(sizeof(int*) * cnt); for (int i = 0; i < cnt; i++) { data[i] = (int*)malloc(sizeof(int) * 3); } } ~hoge() { for (int i = 0; i < dataCnt; i++) { free(data[i]); } free(data); } }; int main(void) { for (int i = 0; i < MAX_LOOP_COUNT; i++) { hoge hoge(ARRAY_SIZE); } }
whitetree

2021/09/24 11:01

質問のソースコードに不備がありまくりで本当申し訳ありません。 実行して確認までしていただいて本当にありがとうございます。 うーん、となると完全に自分が問題だと思っているところと問題の本質がずれていたってことなんですかね...。 itegagaki様のおっしゃる通り別の個所に注意を向けて再度調査してみます
whitetree

2021/09/24 11:39

今色々調べてみていたら、どうやらstd::vectorのpush_backが悪さをしている可能性が浮上してきました。 完全に今回の質問で「関係ないだろー」と思い込んで省いていた箇所でした。お恥ずかしい限りです。 改めて色々調べてみます。 お付き合いいただきありがとうございました。
episteme

2021/09/24 13:28

悪さしてるのは vector<T>::push_back() じゃなくてhogeのコピーが原因とミタ...
whitetree

2021/09/24 13:42

今いろいろと調べていたのですが、どうやら同じ構造体アドレスに対してデストラクタが2回よばれてしまっているのが原因のようでして、もしかしてその原因を作っているのがpush_backということなんでしょうか? 今自分なりにvector::push_backの定義を読んでみてたんですが、いかんせん実力不足で全く挙動について理解できておらず...。 ここがわからんと解決策も見いだせないので頭抱えてます
actorbug

2021/09/24 14:37

この辺の話ではないでしょうか。(リンク先はnew/deleteを使っているが、malloc/freeでも同じ話) 【C++】メンバにポインタを持つクラスの注意点(2重解放、コピーコンストラクタ、代入演算子) https://qiita.com/kamaboko123/items/7a18a9ff3a9becd4c86c
whitetree

2021/09/26 01:20

あーーーー ようやく何とか理解しました(?) 同じ構造体のデストラクタが呼ばれてるってのも見当違いな話で、コピーされた構造体のデストラクタで開放しようとするメモリアドレスがすでに解放されたアドレスにかぶるって話ことか、何もかも間違ってました...。 本当に、皆様こんな初心者の質問にお付き合いいただきありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問