ページ 11

グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 15:28
by tny
また質問させて頂きたいと思います、よろしくお願いします。


グローバル変数を複数ファイルで扱うとき、私の場合は、

グローバル変数宣言用の"GlobalVariable.h"と、GlobalVariable.hで宣言されたグローバル変数をexternするための"ExternGlobalVariable.h"なるヘッダファイルを用意する。
そして、WinMain関数を記述したcppファイルに"GlobalVariable.h"をインクルードし、他の各cpp全てに"ExternGlobalVariable.h"をインクルードする。

と言う手順で実装しています。
しかし、これですと、グローバル変数の内容を変更したいとなったときに、2ファイル分(GlobalVariable.hとExternGlobalVariable.h)変更しなければならず、スマートではなく思われます。
更に、デバッグするとき、ExternGlobalVariable.hを多くのファイルでインクルードしてしまうと、実行までの時間がものすごいかかってしまいます。


これに関して、解決法や改善策がありましたら、ご教授願います。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 15:48
by バグ
グローバル変数を使わなければいいのではないでしょうか?

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 16:28
by tny
一度そうやってゲームを作ってみてるのですが、どうにも都合が悪く感じられてしまって。
シューティングなのですけど、関数の引数が膨大になってしまったり、ちょっとした改造をするにも他の部分へ影響が伝播していってしまうような状況が多発してしまったので。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 16:56
by GPGA
古典的な方法ですが
ExternGlobalVariable.h内部を以下のように記述します。
#ifndef GLOBAL_VARIABLE
	#define EXTERN extern
#else
	#define EXTERN
#endif

// 以下グローバル変数
EXTERN int hoge1;
EXTERN char hoge2;
・・・
 

次に、WinMainを記述したcpp内部では
#define GLOBAL_VARIABLE
#include "ExternGlobalVariable.h"
 

のように呼び出し、他のcpp内部では
#include "ExternGlobalVariable.h"
 

のように呼び出すことで、グローバル変数の記述を一回で済ませることができます。


ただ、私もバグさんが書かれているように、グローバル変数を使わないことをお勧めします。
クラスをうまく使用することで、グローバル変数をひとつも使わずにプログラムを組むことができます。
(クラスを使わなくてもできますが、クラスを使う場合に比べていろいろと面倒です)

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 17:48
by たかぎ
次のような方法もあります。
/* GlobalVariable.h */

struct global_t
{
  int a;
  char b[10];
  double c;
  …
};

extern struct global_t global_variable;

/* GlobalVariable.c */
struct global_t global_variable;
のように、グローバル変数をひとつの構造体に入れてしまう方法です。
この方法の利点は、メンテナンスが楽になるほか、グローバル変数の再初期化を簡単に行うことができるようになることです。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 18:29
by バグ
あら?たかぎさんに先を越されてしまいましたが…(^_^;)

やはり、私も同意見ですね。クラスや構造体をうまく活用すれば、グローバル変数を使用せずにスッキリとしたソースを書く事ができると思います。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 19:01
by たかぎ
私が実際に使っている方法は以下のようなものです。
boost::any& global(const std::string& name)
{
  static std::map<std::string, boost::any> vars;
  return vars[name];
}

void initialize()
{
  global("foo") = 1234;
  global("bar") = "abc";
  global("hoge") = 3.14;
}
こうしておけば、翻訳単位間の初期化順序の問題もクリアできます。
any_cast が面倒なのが難点ですが...

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 19:14
by GPGA
>any_cast が面倒なのが難点ですが...
C++にはvar型がないですからねぇ

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 19:22
by tny
皆様、ご回答ありがとうございます。

GPGAさんのやり方は確かに納得行くのですが、たかぎさんの方法は理解出来ません・・・。
実際に自分でやってみないと把握出来なさそうですので、色々と試してみますね。


しかしあれですね、やはりプロの方はあまりグローバル変数を多用しないのですね。
どういうやり方をすればスッキリいくのかが疑問ですがTT
よろしければ、勉強になりそうなサイト・本etcなどがありましたら、お教えいただけませんでしょうか。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 22:13
by たかぎ
> たかぎさんの方法は理解出来ません・・・。

構造体を使う方は分かりますか?

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 22:27
by tny
あぁすいません、返事を書くのにものすごい文体悩むもので、タイムラグで下二つ分の返事(たかぎさんとGPGAさんのモノ)が見えてませんでした・・・。

構造体の方、色々と猫でも分かるプログラミングやらGoogle経由やらで調べまわっているのですが、それらしいところは見つからずですTT
下の方は、もっと謎ですね・・・まるで初めてソース見たときのような状態です(TT;

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 23:00
by 管理人
え?構造体について書いてあるサイトは沢山ありますよね?
http://www.google.co.jp/search?hl=ja&q= ... %BD%93&lr=

構造体はmemsetを使えば簡単に初期化出来ます。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月27日(水) 23:06
by tny
構造体に関しては、すいません、何か勘違いしてましたo(_ _o
今は分かりました、お手数かけました。


>構造体はmemsetを使えば簡単に初期化出来ます。
これをしてしまうと、とある社長様に怒られそうな予感がしましたもので・・・。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月28日(木) 10:51
by たかぎ
> >構造体はmemsetを使えば簡単に初期化出来ます。
> これをしてしまうと、とある社長様に怒られそうな予感がしましたもので・・・。

C++ですので、memset で初期化するのはお勧めしません。
# Cでもお勧めしませんが...

構造体の各メンバをデフォルトコンストラクタでクリアしたいのであれば、
struct A
{
  …
};

A a;

int main()
{
  a = A();  // クリア
}
とすべきです。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月28日(木) 10:58
by たかぎ
一応、global 関数の方も説明しておきます。
boost::any& global(const std::string& name)
{
  static std::map<std::string, boost::any> vars;
  return vars[name];
}
では、http://www.boost.org/ クラスを使っています。
global 関数の中で定義している vars は、static 指定子が付いていますので、最初に global 関数が呼び出された時点で構築されます。これは、std::string 型の文字列をキーとして、boost::any 型のオブジェクトを引き当てるための連想配列になっています。
すなわち、global 関数は、渡した文字列に対応した変数(オブジェクト)への参照を返しますので、これをあたかもグローバル変数であるかのように使用できるのです。

難があると書いたのは、boost::any から本来の型に明示的なキャストが必要なためです。
例えば、
global("abc") = 123;
int value = any_cast<int>(global("abc"));
のようにです。

Re:グローバル変数を巧いこと複数のファイルで扱う

Posted: 2008年2月28日(木) 16:27
by tny
うーん・・・何よりもまず、Boostと言うのを知りませんでしたので、その勉強から始めた方が良さそう・・・ですかね。
何となくは分かるのですが、そこかしこに理解できない部分があると不安になってしまいますわ・・・。
これ以上突っ込むとスレ違いになりそうですしねTT;