プログラムが死ぬ・・・

[戻る]
KENBO 2006/05/11(木) 16:45:27
VC++6.0 ダイアログベース WindowsXPです。
以下の構造体配列を宣言し、実行すると
死にます。
これはサイズが大きすぎるからなのでしょうか?
PCのメモリは512Mです。

#define MAX_LOG_DATA_NUM    27593 // 最大LOGデータ数
#define MAX_LOG_DATA_LEN    0x64  // 最大LOGデータ長

typedef struct{
    short year;
    char month;
    char day;
    char hour;
    char min;
    char sec;
    short ms;
} TIME_INFO;

// LOG情報構造体
typedef struct{
    TIME_INFO    time;            // 日時時間
    char        code;            // 識別コード
    char        data[MAX_LOG_DATA_LEN];    // LOG情報
} LOG_INFO;

LOG_INFO m_FileLog[MAX_LOG_DATA_NUM];  //##  ←こいつです。

REE 2006/05/11(木) 16:55:28
変数名がm_で始まっていることから、クラスのメンバ変数だと仮定すると、
そのクラスのサイズが3Mバイト以上になります。
また、スタックサイズのデフォルト値は 1Mバイトですので、
そのクラスのインスタンスをローカル変数とするなどで、スタック上に作成すると、
確実にスタックオーバーフローします。

クラスのインスタンスをヒープから確保するか、
このメンバ変数を動的確保で保持するようにしましょう。

Ban 2006/05/11(木) 16:57:43
> これはサイズが大きすぎるからなのでしょうか?

十中八九そうですね。
PCのメモリ以前に、スレッド内で使える「スタックサイズ」が、
VC6のデフォルトでは1MBしかありません。(他のデータなども合わせて、1MB)
上記を自動変数で確保しているなら「スタックオーバフロー」します。

new 等で動的に確保してみてください。

たいちう 2006/05/11(木) 17:00:33
> 以下の構造体配列を宣言し、実行すると
> 死にます。

コンパイルはできているんですね?
じゃあ現象は違うと思うのですが、私の環境ではコンパイルもできませんでした。

原因はdefineの数字の後の全角スペースでした。

KENBO 2006/05/11(木) 17:07:52
REEさん、ありがとうございます。
クラスのメンバ変数です。
3M以上はダメなのですね?初めて知りました。
ちなみにデバッグモードで実行すると、スタックオーバーフローとエラーがでました。

1.このクラスのcppファイルの先頭でグローバル宣言すれば大丈夫ですよね!?
2.new演算子を使って動的にこのクラスのヘッダファイル内でメンバ変数として宣言し
  ても平気なのですか?そうするとこのクラスのメンバ変数として扱えるようになる
がメモリはヒープエリアから用いているということになりますかね?


ちなみに、ヒープエリアのサイズ制限はあるのですか?

REE 2006/05/11(木) 17:25:58
>3M以上はダメなのですね?初めて知りました。

3M以上と書いたのは、そのデータがそれくらいの大きさという意味で、
理由からも分かるとおり、デフォルトでは、1M以上でだめです。
(実際にはスタックは他の用途にも使われるので、1M未満でも1Mに近いとだめです。)

>1.このクラスのcppファイルの先頭でグローバル宣言すれば大丈夫ですよね!?
大丈夫ですが、グローバルにするくらいなら、
staticメンバ変数にした方がいいかもしれません。

>2.new演算子を使って動的にこのクラスのヘッダファイル内でメンバ変数として宣言し
>  ても平気なのですか?そうするとこのクラスのメンバ変数として扱えるようになる
>がメモリはヒープエリアから用いているということになりますかね?

メンバ変数の宣言と同時にnew演算子で初期化しようとしているなら無理です。
普通は、配列の変わりにポインタで宣言し、
コンストラクタなどで、new演算子で確保します。(もちろんデストラクタで解放)

また、本題からは外れますが、常に最大のサイズが必要ということでなければ、
可変配列(CArray,std::vector)や文字列クラス(CString,std::string)などを使うのも手
です。

>ちなみに、ヒープエリアのサイズ制限はあるのですか?

無限に取れるわけはないので、もちろんありますが、ギガバイト単位の話です。

KENBO 2006/05/11(木) 17:36:51
REEさん、色々ありがとうございます。勉強になります。
クラスのメンバ変数というのは、スタック領域に割り当てられるのですね?

>staticメンバ変数にした方がいいかもしれません。
これで宣言するとスタックオーバーフローにはならないのですか?

ちなみに、static演算子については、使ったことがないわけではないのですが(VCでは
ない)、ほとんど使い方をしりません。どういうとき使ったらいいのかわかりません。
グローバル変数との違いがよくわかりません。

KING・王 2006/05/11(木) 17:54:25
> クラスのメンバ変数というのは、スタック領域に割り当てられるのですね?
違います。
クラスのインスタンスがスタック領域に確保された場合は、当然そのメンバ変数もスタックに割
り当てられます。
クラスのインスタンスをヒープ領域に確保すれば、メンバ変数は当然ヒープ領域になります。

staticにすると、スタックとは別領域(グローバルと同じような領域)に確保されます。

> ちなみに、static演算子については、
> (省略)
> グローバル変数との違いがよくわかりません。

とりあえず、staticとグローバルではスコープが異なります。
グローバルはどこからでもアクセスできますが、
staticなオブジェクトは、翻訳単位外から直接アクセスすることができません。

KENBO 2006/05/11(木) 18:14:20
>クラスのインスタンスがスタック領域に確保された場合
これは、ようするにローカルで別クラスの宣言をした時とかですかね?

REE 2006/05/11(木) 18:32:41
まず、staticとグローバルは相反するものではありません。
グローバルかどうかは宣言・定義の位置で決まります。
staticはそれに対する修飾です。

とりあえず、変数の種類とスコープと一般的な記憶域です。

・staticグローバル変数・・・翻訳単位からアクセス可能・・・静的記憶領域
・非staticグローバル変数・・・どこからでもアクセス可能・・・静的記憶領域
・staticメンバ変数・・・publicならどこからでもアクセス可能・・・静的記憶領域
・非staticメンバ変数・・・publicならどこからでもアクセス可能・・・それをメンバに
持つクラス,構造体と同じ領域
・staticローカル変数・・・関数内でアクセス可能・・・静的記憶領域
・非staticローカル変数・・・関数内でアクセス可能・・・スタック


>>クラスのインスタンスがスタック領域に確保された場合
>これは、ようするにローカルで別クラスの宣言をした時とかですかね?
そうです。(厳密には宣言ではなく定義)

KENBO 2006/05/12(金) 09:16:48
>グローバルかどうかは宣言・定義の位置で決まります。
>staticはそれに対する修飾です。
これはわかってます。よくわからないのは使い方です。
Cでも同じだと思いますが、【staticグローバル変数】はどういう時に使いますか?グロ
ーバルの場合、staticにする意味があるとは思えないのですが・・・

>翻訳単位
これはどういう意味ですか?

1.1M以上の【非staticメンバ変数】を宣言して実行するとなぜオーバーフローするの
でしょうか?
スタック領域に割り振られないのなら平気なのでは?

2.クラスAで【protected】でメンバ変数を定義したものは、
クラスBでクラスAのインスタンスを定義してもアクセスできないですよね?(public
だけアクセス可能)
クラスA内の変数、関数に他クラスからまったくアクセスしない場合は、
public、prootectedの区別をつける意味はないという認識でいいでしょうか?
まとめると、意味はおよそ理解してるが、prootectedで定義したほうがよいというよう
な状況がわからないのでpublicでしか定義したことがないのです。
REEさんはどういう時に使い分けますか?

REE 2006/05/12(金) 09:38:52
>>翻訳単位
>これはどういう意味ですか?
簡単に言うと、一つの拡張子がc(又はcpp)のファイルです。


>1.1M以上の【非staticメンバ変数】を宣言して実行するとなぜオーバーフローするの
でしょうか?
>スタック領域に割り振られないのなら平気なのでは?

・非staticメンバ変数・・・それをメンバに
持つクラス,構造体と同じ領域
・非staticローカル変数・・・スタック

それをもつクラスが非staticローカル変数として作成されるとスタック領域に割り振られ
ます。


>2
>関数に他クラスからまったくアクセスしない場合
間違って参照したときにエラーになるように
出来るだけprotected又は、privateにします。
そのための指定です。

>REEさんはどういう時に使い分けますか?
必然性が無い時は、指名して質問しないようにしましょう。
必然性がある場合:他の人の回答では意味がない場合

KENBO 2006/05/12(金) 10:03:46
>必然性が無い時は、指名して質問しないようにしましょう。
ごもっともです。失礼しました。

>非staticローカル変数・・・スタック
>それをもつクラスが非staticローカル変数として作成されるとスタック領域に割り振
>られます。
これはもちろんわかります。
でも今回の場合、【非staticメンバ変数】なのですが・・・

KENBO 2006/05/12(金) 10:08:19
>間違って参照したときにエラーになるように
>出来るだけprotected又は、privateにします。
なるほど。基本はprivateで定義して、もし他クラスからアクセスするような状況になっ
た物だけpublicに変更する。って感じでコーティングを進めたほうがよいということで
すね。

Ban 2006/05/12(金) 10:19:27
> でも今回の場合、【非staticメンバ変数】なのですが・・・

ということは当然、そのクラス自体がスタック上に確保されると、
メンバ変数の方もスタックに確保され、そこでオーバフローしますね。
> それをメンバに持つクラス,構造体と同じ領域

# > なるほど。基本はprivateで定義して、もし他クラスからアクセスするような状況になっ
# > た物だけpublicに変更する。って感じでコーティングを進めたほうがよいということですね。
# 一つの考え方として間違ってはいない気もしますが、コーディング中にそうころころと
# 変わるものではないと思います。最初から public にしておいた方がいいものもあるので。
# 「オブジェクト指向」とか「カプセル化」、「隠蔽」とか調べてみるとよいかと。

KENBO 2006/05/12(金) 10:35:28
>最初から public にしておいた方がいいものもあるので。
それはもちろんそうですよね。
ちょっとおおざっぱに書いちゃいましたが・・
定義するときに、まぁこいつは他クラスからアクセスすることはないだろうって思った
変数は全てprivateで定義するべきだということを言いたかったのです。


>そのクラス自体がスタック上に確保されると
これは、他クラスでそのクラスのインスタンスを定義したときのみ起きる現象ですよ
ね?
今回の、LOG_INFO m_FileLog[MAX_LOG_DATA_NUM];  は、定義しているだけで
同クラス内でもアクセスしていません。
このクラスのインスタンスを他クラスでは定義してないのですが・・・
だから、自分はスタックにこの変数が確保されることはないと思ってるんですが・・・
間違ってますか?

Ban 2006/05/12(金) 11:28:02
> >そのクラス自体がスタック上に確保されると
> これは、他クラスでそのクラスのインスタンスを定義したときのみ起きる現象ですよね?

いいえ。他クラスに限りません。自動変数などでも発生します。

そして、そのメンバを持っているのが、仮に CXxxxDlg だとすれば、VCのスケルトンコードの
InitInstance の中で自動変数にとられてますから、ここでスタックオーバフローするでしょう。

> 今回の、LOG_INFO m_FileLog[MAX_LOG_DATA_NUM];  は、定義しているだけで

具体的に m_FileLog が定義されているクラスはなんですか。定義を開示してください。

> 同クラス内でもアクセスしていません。

定義された時点で問題となりますので、アクセスの有無とは無関係です。

> このクラスのインスタンスを他クラスでは定義してないのですが・・・
> だから、自分はスタックにこの変数が確保されることはないと思ってるんですが・・・
> 間違ってますか?

間違っています。
前述のように、他クラスで定義しなくても、そのクラス自身が自動変数として確保されれば、
その領域はスタックに確保されます。

KENBO 2006/05/12(金) 11:44:51
>具体的に m_FileLog が定義されているクラスはなんですか。定義を開示してくださ
い。
CXxxxDlgです。

>そして、そのメンバを持っているのが、仮に CXxxxDlg だとすれば、VCのスケルトン
>コードのInitInstance の中で自動変数にとられてますから、ここでスタックオーバフ
>ローするでしょう。
これは知らなかったです。

言い換えてまとめると、

クラスCXxxxDlgで定義した、メンバ変数、メンバ関数は全てInitInstance()内で自動変
数となり、スタック領域に確保される。
だから、1Mを超える領域を定義するとスタックオーバーフローで死ぬ。
メンバ変数、メンバ関数をstaticで定義すると、
スタック領域には確保されず、静的記憶領域に確保されるのでOK!

ということですね?

え〜いち 2006/05/12(金) 15:31:53
そもそも質問から考えて、staticにすべきではないと思います
staticに場合はどんなときかを考えないと・・・
で、少なくとも今回の質問の回答からすると、スタックに取れない(取るべきでもないか
な)データだと思われるので、newすべきだと思います
どーーーしても、スタックにとりたいなら、スタックサイズを変更することもできます
が、KENBOさんの今回の解決方法としてはよろしくないですね

それから、変数のpublic定義など、ここ数年のやったことがありません
publicにする理由に出会ったことがありません
VC++のClassWizardでメンバ変数の追加するとpublicにあります
何でかとっても悩んでしまいます・・・

REE 2006/05/12(金) 15:36:16
>定義するときに、まぁこいつは他クラスからアクセスすることはないだろうって思った
>変数は全てprivateで定義するべきだということを言いたかったのです。

他から勝手にアクセス出来ては困る変数→private or protected
他からアクセスする必要のない変数→private or protected
他からアクセスする必要のある変数→public


>クラスCXxxxDlgで定義した、メンバ変数、メンバ関数は全てInitInstance()内で自動変
数となり、スタック領域に確保される。

メンバ関数はstaticの有無に関わらず、普通はスタック領域には置かれません。
普通の関数と同じようにプログラム領域に置かれます。

メンバ変数が直接自動変数になるわけではありません。(似たようなものですが・・)

KENBO 2006/05/12(金) 16:47:38
>どーーーしても、スタックにとりたいなら
そんなことはありません。
現時点で他の方法がわからないだけです。

>少なくとも今回の質問の回答からすると、スタックに取れない(取るべきでもないか
>な)データだと思われるので、newすべきだと思います
newで動的領域確保のほうがよいということですか!?
その場合って、コンストラクタ/デストラクタというのを用いるのですか?
そうすれば、メンバ変数と同様の扱いができるのですか?
コンストラクタ/デストラクタを使ったことない(使い方を知らない)のですが・・・

例えば、CxxxDlgというクラスなら、
CxxxDlg.hで、
class CxxxDlg : public CDialog
{
// 構築
private:
    LOG_INFO m_FileLog[MAX_LOG_DATA_NUM];  // 一番上の定義
    LOG_INFO *mp_buf;
    CxxxDlg();
    ~CxxxDlg();
}

として、
CxxxDlg.cppで、
void CxxxDlg::CxxxDlg()
{
    mp_buf = new LOG_INFO[MAX_LOG_DATA_NUM];
}
void CxxxDlg::~CxxxDlg()
{
    delate[] mp_buf;
}
と実体を作る。

こんな使い方になりますか?

KENBO 2006/05/12(金) 16:49:15
上記、
private:
>    LOG_INFO m_FileLog[MAX_LOG_DATA_NUM];  // 一番上の定義
削除です。間違えました。

Ban 2006/05/12(金) 17:20:24
> 削除です。間違えました。
これを込みで、イメージはそうですね。

ダイアログベースで CDialog の派生なら用法的に大丈夫かもしれませんが、
自分でポインタをもつと、本来
CxxxDlg::CxxxDlg(const CxxxDlg&)//コピーコンストラクタ
CxxxDlg::operator =(const CxxxDlg&)//コピー演算子
とか考慮する必要があります。

なので、REE さんが既に書かれているように、std::vector<LOG_INFO>という方が
正攻法かもしれません。(これだと、副作用で(?)ログ数を可変長で保持できます。

KENBO 2006/05/12(金) 17:58:59
>std::vector<LOG_INFO>という方が正攻法かもしれません。
これは、いったい何者ですか?
使い方がまったくわかりません。
また、ドコで使えばいいですか?

「使用上の注意」を必ずお読み下さい。 2006/05/12(金) 18:05:19
std::vectorは動的配列を扱えるクラスです。(可変長配列みたいなもの)
一度Google等の検索エンジンで探してみるとサンプルがゴロゴロとあります。

MFCならば、REEさんもおっしゃっていましたが、CArrayというクラスがあります。
こちらもGoogle等で探してみてください。

Blue 2006/05/12(金) 18:09:15
> 使い方がまったくわかりません。

簡単な使い方を説明したサイトです。参考にどうぞ。
http://www1.kcn.ne.jp/~robe/cpphtml/html04/cpp04005.html

でも、私の場合、MFCであれば CArray を使いますね。
(一部だけSTLを使うと気持ちが悪いので)

KENBO 2006/05/12(金) 18:31:02
CArrayも使ったことないので
調べてやってみます。
ありがとうございます。

KENBO 2006/05/16(火) 11:46:07
[[解決]]
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200605/06050043.txt

に続きのスレをたてました。
【プログラムが死ぬ・・・】原因は理解したので
このスレは解決とします。
ありがとうございました。

古いスレッドには追加発言できません。