【雑談】グローバル変数について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
たかぎ

【雑談】グローバル変数について

#1

投稿記事 by たかぎ » 14年前

先日もグローバル変数についての質問がありました。そこに便乗してもよかったのですが、改めて質問しなおすことにします。
グローバル変数についてみなさんのご意見をお聞かせください。
質問は次の4つです。

1. グローバル変数とは何か?
2. グローバル変数のメリット
3. グローバル変数のデメリット
4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?

上記について、Cの場合、C++の場合それぞれについて教えてください。
どちらか一方だけでもかまいませんが、CなのかC++なのかを明確にしてください。

以上です。
よろしくお願いします。

Dixq (管理人)

Re:【雑談】グローバル変数について

#2

投稿記事 by Dixq (管理人) » 14年前

面白い話題ですね、是非私もたかぎさんの意見をお伺いたいです。

では私の意見を述べておきます。
また、C++でグローバル変数は必要ないと思うので、Cに限定して書きます。

===========================================================================

1.グローバル変数とは何か

何か・・というとどう答えていいのかわかりませんが、ANSIC言語辞典には「広域的に使われる変数で内部結合と外部結合の変数をいう」と書いてありました。
自分の言葉で言うならば「あらゆるスコープから参照出来る変数」・・でしょうか。

2.グローバル変数のメリット

モジュールごとに関数間で同じ変数にアクセスできる事。
クラスのメンバ変数と同じように使う使い方ならば、なんちゃってクラスみたいな感じで使える事。(グローバル変数は必ずstaticに)
グローバル変数なしで大きなシステムを作ろうとするとこれでもかと言わんばかりに関数の引数が増えたり独自の構造体のオンパレードになりそうです。
既にご覧になっていると思いますが、詳しくはhttp://www.play21.jp/board/formz.cgi?ac ... &rln=63044ということで・・。

3.グローバル変数のデメリット

モジュールごとにファイルわけをしておき、グローバル変数をstaticにしておけばそんなにデメリットは無いのではないかと思いますがそうではないどこからでも参照出来るグローバル変数を使った設計であるという前提の元以下列挙します。

・どんな場所からでもアクセスできる為危険
・人の書いたプログラムだとどこで何が書き換わってるのかわけがわからない。
・モジュールをまたいだグローバル変数は再利用性や独立性を下げる。
・単体テストなどが行いにくくなる。
・大きなシステムでは重複しない名前の管理が少し大変?
・newでクラスを作るのとは違ってメモリを最初から食ってしまう(ポインタだけ宣言しておいてmallocすればよいのですが)
・ローカル変数は初期化せずに使うと怒られるが、グローバル変数は宣言すると値が最初から0になっているので、初期化漏れを見逃しやすく、ゲームをリセットした時に動作が変わる可能性がある
・ローカル変数で同じ変数名を宣言すると、同じ名前の変数が二つ存在する事になり、誤解の元になる(追記)

・・位でしょうか。他にも思いついたら追記します。

4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?

goto文のように「とりあえず使うな」で通す方が良いのではないでしょうか。
グローバル変数を使わなければ作れないシステムは無いですし、
不適切なグローバル変数の使用によるリスクと、グローバル変数を使わない事による少々の非効率を考えたら、
「とりあえず使うな」で通す方が簡単なのではないかと思います。
しっかりと指導出来る環境や明確な設計方針がある場合であれば話は別ですが。

===========================================================================

私もこの件は非常に興味があるのでコメントさせて頂きましたm(_ _)m
(追記:4.を書きそびれていたので追記しました)

追記:
欠点:
static変数を使ったとしても、そのモジュールは一つのモジュールとしてしか処理出来ない。
やはりクラスのようにポンポン作れるものではないからこういうのは難しいですね・・。

Poco

Re:【雑談】グローバル変数について

#3

投稿記事 by Poco » 14年前

> 1. グローバル変数とは何か?

プログラム全体に渡って重要な変数(C/C++)

> 2. グローバル変数のメリット

main()が実行される前に、初期化が済んでいること(C/C++)

> 3. グローバル変数のデメリット

書き換えが簡単に行えること(C/C++)

> 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?

取り敢えず、自由に書かせる(コーディング規約には従わせる)。
レビュー時にフルボッコにするべき。

シエル

Re:【雑談】グローバル変数について

#4

投稿記事 by シエル » 14年前

1. グローバル変数とは何か?
→どこからもアクセスできる変数。

2. グローバル変数のメリット
→どこからもアクセスできるから共有したいときに便利。

3. グローバル変数のデメリット
→どこからでも変更できてしまうこと。

4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
→使わせない。困ったら随時質問してきてもらう。

たかぎ

Re:【雑談】グローバル変数について

#5

投稿記事 by たかぎ » 14年前

みなさん、コメントありがとうございます。

順番にお返事していきます。
まずは、Dixqさんから

> また、C++でグローバル変数は必要ないと思うので、Cに限定して書きます。

これはなぜそう思いますか?
C++でも、std::coutのようなグローバル変数はふつうに使われていますよね?

> 何か・・というとどう答えていいのかわかりませんが、ANSIC言語辞典には「広域的に使われる変数で内部結合と外部結合の変数をいう」と書いてありました。
> 自分の言葉で言うならば「あらゆるスコープから参照出来る変数」・・でしょうか。

これは矛盾していませんか?
内部結合の変数も含むのであれば、異なる翻訳単位からは参照できません。
実は、このあたりの線引きをみなさんどう考えているのが知りたいのです。

> モジュールごとに関数間で同じ変数にアクセスできる事。

内部結合の変数をグローバル変数とするのであれば、これはおかしくないでしょうか?

> クラスのメンバ変数と同じように使う使い方ならば、なんちゃってクラスみたいな感じで使える事。(グローバル変数は必ずstaticに)

すみません。これはあまりよくわかっていません。

> グローバル変数なしで大きなシステムを作ろうとするとこれでもかと言わんばかりに関数の引数が増えたり独自の構造体のオンパレードになりそうです。

パフォーマンスさえ気にしなければそうでもないと思います。
極端な話、グローバル変数の代わりにアクセッサを設けてもよいわけですよね。

> モジュールごとにファイルわけをしておき、グローバル変数をstaticにしておけばそんなにデメリットは無いのではないかと思いますがそうではないどこからでも参照出来るグローバル変数を使った設計であるという前提の元以下列挙します。
> (以下省略)

まあ、よくいわれているところですね。
ある程度は回避可能なものもありますが、確かに問題はあります。

> goto文のように「とりあえず使うな」で通す方が良いのではないでしょうか。

そうですね。
ただ、私なんかは、グローバル変数を禁止すると、下記のような回避策をとるプログラマが出てきそうで不安です。

int *global_a(void)
{
static int a;
return &a;
}

このような関数を用意して、返したポインタを持ち回るという回避策です。
これだと、下手をすればグローバル変数以上に凶悪になってしまいます。
つまり、グローバル変数を直接使うのであれば、検索すれば使用箇所を簡単に特定できますが、ポインタで持ち回られると追跡が極めて困難になります。
スキルが低いと、こんな抜け穴は思いつかないのでしょうかね?
画像

Dixq (管理人)

Re:【雑談】グローバル変数について

#6

投稿記事 by Dixq (管理人) » 14年前

あ、後ここでこんな事を書いてもいいのか解りませんが、
最近のたかぎさんのHPでベターCの本が書いてみたいと書かれていましたよね。
Cでモジュール管理をするにはどのようにするべきなのか、
Cでなんちゃってクラスを作るならばどのようにするべきなのかなど色々聞いてみたいなと個人的に思いました^^

たかぎ

Re:【雑談】グローバル変数について

#7

投稿記事 by たかぎ » 14年前

ぽこさん

> > 1. グローバル変数とは何か?
> プログラム全体に渡って重要な変数(C/C++)

この意見は初めて聞きました。
アクセスできる範囲ではなくて、重要性によってグローバル変数かどうかが決まるということでしょうか?

> > 2. グローバル変数のメリット
> main()が実行される前に、初期化が済んでいること(C/C++)

C++の場合、規格上は保証されません。まあ、見かけ上は同じことですけど。
逆に、(C++の場合ですが)翻訳単位間で初期化順序が不定になることがデメリットになる気もしますが、それについてはどうでしょうか?

> > 3. グローバル変数のデメリット
> 書き換えが簡単に行えること(C/C++)

これはメリットでもデメリットでもあるでしょうね。
const修飾されたグローバル変数であれば、書き換えられる心配はないので、デメリットはないと考えてよいでしょうか?
あと、グローバル変数を「プログラム全体に渡って重要な変数」と定義するのであれば、「書き換えが簡単に行えること」につながらない気がするのですが...

> > 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
> 取り敢えず、自由に書かせる(コーディング規約には従わせる)。
> レビュー時にフルボッコにするべき。

確かにこれには一理ありますね。

たかぎ

Re:【雑談】グローバル変数について

#8

投稿記事 by たかぎ » 14年前

> あ、後ここでこんな事を書いてもいいのか解りませんが、
> 最近のたかぎさんのHPでベターCの本が書いてみたいと書かれていましたよね。
> Cでモジュール管理をするにはどのようにするべきなのか、
> Cでなんちゃってクラスを作るならばどのようにするべきなのかなど色々聞いてみたいなと個人的に思いました^^

その話は別トピでやりましょう。

たかぎ

Re:【雑談】グローバル変数について

#9

投稿記事 by たかぎ » 14年前

シエルさん

> 1. グローバル変数とは何か?
> →どこからもアクセスできる変数。

ということは、内部結合の変数やpublic以外の静的データメンバのようなものは含まないと考えてよろしいですね。

> 2. グローバル変数のメリット
> →どこからもアクセスできるから共有したいときに便利。

> 3. グローバル変数のデメリット
> →どこからでも変更できてしまうこと。

やはり、この部分は一長一短ということでしょうか。
ぽこさんへのお返事でも書きましたが、const修飾されたグローバル変数であれば、書き換えられる心配はないので、デメリットはないと考えてよいでしょうか?

> 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
> →使わせない。困ったら随時質問してきてもらう。

これもDixqさんへのお返事で書きましたが、簡単に脱法行為ができてしまうんですよね。
それについてはどうお考えでしょうか?

dic

Re:【雑談】グローバル変数について

#10

投稿記事 by dic » 14年前

1. グローバル変数とは何か?
 どこからもアクセスできる変数(構造体のインスタンス)

2. グローバル変数のメリット
 どこからでも変更、設定できるので便利

3. グローバル変数のデメリット
 どこからでも変更、設定できるので、デバッカで追うのがつらい
 設定の変更の範囲が全体に渡るので、影響範囲が大きい

4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
 グローバル変数の名前にそのメンバーの名前を変数に使用する

アセンブラになってもうしわけないですが
汎用レジスタと同じような役割と思ってます

Dixq (管理人)

Re:【雑談】グローバル変数について

#11

投稿記事 by Dixq (管理人) » 14年前

> 下記のような回避策をとるプログラマが出てきそうで不安です

私は関数内でstatic変数を使う事はグローバル変数をむやみに使う以上に危険だと思うのですがいかがでしょう?
モジュール内のstatic変数を全初期化しようとするとすごくめんどくさいことになりそうですし、
初期化漏れも起きそうな気がします。
私はグローバル変数禁止を初心者に布教するなら関数内static変数の禁止を布教したいような気がします・・。

> これはなぜそう思いますか?

C++はシングルトンがあるので・・って意味でした。

> 実は、このあたりの線引きをみなさんどう考えているのが知りたいのです。

単純なグローバル変数は外部結合、staticを付けると内部結合なのではないでしょうか。

> すみません。これはあまりよくわかっていません。

「なんちゃってクラス」なんて言葉が悪かったですかね。
特定のモジュールに必要な関数が集まった単位の中だけで共有できる変数を用意出来るという意味です。

class xx{
int a;
void func1();
void func2();
};

xxクラスのfunc1とfunc2は同じaを共有出来ますが、Cでそれをやろうとすると、
ファイルの区切りをクラスの区切りと同じように見立てて、ファイルの先頭で

static int a;

してやれば、似たような事が出来るのではないかという事です。
しかしこれは追記にも書いた通り、2つ以上モジュールに同時に異なる仕事がさせられないという欠点がありますね。
Cでモジュールを作る設計として正しい設計方法は私も知りたいところです。

たかぎ

Re:【雑談】グローバル変数について

#12

投稿記事 by たかぎ » 14年前

dicさん、コメントありがとうございます。

Cについてでしょうか? C++についてでしょうか?
以下、両方に共通のご意見だと解釈して書きます。

> 1. グローバル変数とは何か?
>  どこからもアクセスできる変数(構造体のインスタンス)

グローバル変数は構造体ということでしょうか?

> 2. グローバル変数のメリット
>  どこからでも変更、設定できるので便利

> 3. グローバル変数のデメリット
>  どこからでも変更、設定できるので、デバッカで追うのがつらい
>  設定の変更の範囲が全体に渡るので、影響範囲が大きい

やはりどこからでも書き込めることがメリットでもデメリットでもあるということですね。
ということは、const修飾されたグローバル変数なら書き込めないのでデメリットはないことになりますね。
あと、デバッガにもよりますが、特定のアドレスに書き込んだときにブレークをかけることもできるので、それであればデバッガで追うのは多少は楽になりませんか?

> 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
>  グローバル変数の名前にそのメンバーの名前を変数に使用する

罰ゲームみたいですね。

シエル

Re:【雑談】グローバル変数について

#13

投稿記事 by シエル » 14年前

>ということは、内部結合の変数やpublic以外の静的データメンバのようなものは含まないと考えてよろしいですね。
→いいです。

>やはり、この部分は一長一短ということでしょうか。
>ぽこさんへのお返事でも書きましたが、const修飾されたグローバル変数であれば、書き換えられる心配はないので、デメリットはないと考えてよいでしょうか?

→う~ん。どうでしょうね。まあ書き換えられる心配はなくなりますが、
 なんかソースが汚くなるイメージがあります。
 あの変数どこのファイルにあったっけ?とか。
 まあ、それは私の管理方法に問題があるんでしょうけどw

>これもDixqさんへのお返事で書きましたが、簡単に脱法行為ができてしまうんですよね。
>それについてはどうお考えでしょうか?

→私はそんなワガママな人とあまり一緒に仕事したくないですねw
 防止する方法が思いつかないので、そのメンバーを信じるしかないですねw変な意見ですみません^^;

たかぎ

Re:【雑談】グローバル変数について

#14

投稿記事 by たかぎ » 14年前

Dixqさん

> 私は関数内でstatic変数を使う事はグローバル変数をむやみに使う以上に危険だと思うのですがいかがでしょう?

私はそうは思いません。

> モジュール内のstatic変数を全初期化しようとするとすごくめんどくさいことになりそうですし、
> 初期化漏れも起きそうな気がします。

その関数の設計者が知らない方法で初期化される方が危険ではないでしょうか?
再初期化が必要な状況では、再初期化の対象になるオブジェクトや再初期化の方法をしっかり設計すべきですし、あとから強引な初期化を行うべきではないと思います。
C++だとなおさらで、POD型以外はそういった強引な初期化は通用しませんよね。

> 私はグローバル変数禁止を初心者に布教するなら関数内static変数の禁止を布教したいような気がします・・。

もしこれができないと、特にC++では非常に困る気がします。

> C++はシングルトンがあるので・・って意味でした。

シングルトンだと、同じ型のオブジェクトを複数作れませんよね。

> 単純なグローバル変数は外部結合、staticを付けると内部結合なのではないでしょうか。

そうなんですが、staticを付けたり、無名名前空間内で定義した変数はグローバル変数なのでしょうか? それとも違うのでしょうか?

> 「なんちゃってクラス」なんて言葉が悪かったですかね。
> 特定のモジュールに必要な関数が集まった単位の中だけで共有できる変数を用意出来るという意味です。

了解です。
ただ、書かれているように、その方法では多重化ができませんね。

たかぎ

Re:【雑談】グローバル変数について

#15

投稿記事 by たかぎ » 14年前

シエルさん

> →う~ん。どうでしょうね。まあ書き換えられる心配はなくなりますが、
>  なんかソースが汚くなるイメージがあります。
>  あの変数どこのファイルにあったっけ?とか。
>  まあ、それは私の管理方法に問題があるんでしょうけどw

私なんかは、マクロで定数を定義するよりはずっと健全だと考えています。
Cの集成体やC++のクラス型のオブジェクトをマクロ定数にするのは無理がありますし。

> →私はそんなワガママな人とあまり一緒に仕事したくないですねw
>  防止する方法が思いつかないので、そのメンバーを信じるしかないですねw変な意見ですみません^^;

ワガママかどうかはわかりませんよ。
(少なくともその人の能力では)数カ所から設定・参照できる変数を使わないと機能を実現できないけれど、グローバル変数は禁止されている。
そこで、苦心の末に見つけた解決策かもしれません。

結局、こうした問題が起きるのは、グローバル変数という「形式」を禁止するだけでは、その心が相手に伝わらないからだと思います。
グローバル変数がどこからでも変更できるから問題だとするのであれば、どこからでもグローバルな設定を変えられるような関数(例えばsetlocaleなど)がなぜ禁止されないのか、そこをきちんと説明できなければならないと思います。

誤解のないように補足しておくと、setlocaleは具体例として挙げただけで、同じようなグローバル設定のための関数はいくらでもありますし、いくらでも作れます。それらをどう考えるのかまで踏み込まなければ、どこからでも変更できるからという理由だけで禁止するのは無理があると思うのです。

lriki

Re:【雑談】グローバル変数について

#16

投稿記事 by lriki » 14年前

興味深いお話ですね。皆さんの意見、参考になります。

私は基本的に C++ しか使わないのでその方向で書かせていただきます。


1. グローバル変数とは何か?

クラスのインスタンス置き場。


2. グローバル変数のメリット

使いたいときにアクセスできる。


3. グローバル変数のデメリット

どこからでもアクセスできるので、どこで値が変わったかわからない。

配列の範囲外アクセスが起こった場合、エラーで落ちないで後ろで宣言した変数の内容が変わる…。
int gAry[ 8 ];
int gValue; // gAry[ 8 ] = 値; で…


4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?

私の場合は「さわらないで」っていうのが第一です。

ほんとに何が起こるか分からない場合、Global みたいなクラスを作って、メンバにグローバル変数を全部置いておきます。
そのあと、Global をシングルトンで実装します。手間はかかりますけど…^^;

Poco

Re:【雑談】グローバル変数について

#17

投稿記事 by Poco » 14年前

> > > 1. グローバル変数とは何か?
> > プログラム全体に渡って重要な変数(C/C++)
>
> この意見は初めて聞きました。
> アクセスできる範囲ではなくて、重要性によってグローバル変数かどうかが決まるということでしょうか?

逆です。
グローバル変数だから重要なんです。
オブジェクトを隠蔽せずに、名前をつけ、コードを読む人に知らしめるだけの必要性、必然性があるんです、絶対。
無いなら敢えてグローバル変数にする必要はないと考えています。

> > > 2. グローバル変数のメリット
> > main()が実行される前に、初期化が済んでいること(C/C++)
>
> C++の場合、規格上は保証されません。まあ、見かけ上は同じことですけど。
> 逆に、(C++の場合ですが)翻訳単位間で初期化順序が不定になることがデメリットになる気もしますが、それについてはどうでしょうか?

#保証されてなかったのか。。。
これはメリットと同格であるデメリットに該当しないと考えています。
メリットを享受するうえでの、「制限」もしくは「注意事項」といったものでしょうか。

> > > 3. グローバル変数のデメリット
> > 書き換えが簡単に行えること(C/C++)
>
> これはメリットでもデメリットでもあるでしょうね。
> const修飾されたグローバル変数であれば、書き換えられる心配はないので、デメリットはないと考えてよいでしょうか?

考えて良いと思います。
#だた、これは「変数」じゃなくて「定数」ですよね。

> あと、グローバル変数を「プログラム全体に渡って重要な変数」と定義するのであれば、「書き換えが簡単に行えること」につながらない気がするのですが...

あれ?重要な変数だからこそ、どこからでも(という言葉を付けてさせてください^^;)
書き換えが簡単に行えることはデメリットだと思うのですが。

たかぎ

Re:【雑談】グローバル変数について

#18

投稿記事 by たかぎ » 14年前

りゅんさん、コメントありがとうございます。

> 1. グローバル変数とは何か?
> クラスのインスタンス置き場。

これって記憶域の話では?

> 2. グローバル変数のメリット
> 使いたいときにアクセスできる。

C++だとそうはいかないのでは?
翻訳単位にまたがる非局所オブジェクトの動的初期化の順序は不定なので、それらのコンストラクタや初期化子の中で他のグローバル変数にアクセスするのは結構大変だと思うのですが...

> 3. グローバル変数のデメリット
> どこからでもアクセスできるので、どこで値が変わったかわからない。
>
> 配列の範囲外アクセスが起こった場合、エラーで落ちないで後ろで宣言した変数の内容が変わる…。
> int gAry[ 8 ];
> int gValue; // gAry[ 8 ] = 値; で…

少なくともこの例であれば、グローバル変数が悪いのではなく、範囲外アクセスが悪いのではないかと思います。
自動変数でも範囲外アクセスが起きると、エラーで落ちないで動作が変わるだけのことは普通にありますので。
また、グローバル変数を

std::vector<int> gAry(8);

としておいて、

gAry.at(8) = 値; とすれば例外が送出されるので、この問題は回避できます。
この二点から、これはグローバル変数の問題とは違う気がするのですが、いかがでしょうか?

> 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
> 私の場合は「さわらないで」っていうのが第一です。

これはグローバル変数がすでに存在していることが前提ですか?
新規に作ることについてはどうでしょうか?

> ほんとに何が起こるか分からない場合、

何が起こるか管理されていないことの方が問題のように思いますが、どうなのでしょうか?

たかぎ

Re:【雑談】グローバル変数について

#19

投稿記事 by たかぎ » 14年前

ぽこさん

> 逆です。
> グローバル変数だから重要なんです。
> オブジェクトを隠蔽せずに、名前をつけ、コードを読む人に知らしめるだけの必要性、必然性があるんです、絶対。
> 無いなら敢えてグローバル変数にする必要はないと考えています。

なるほど。おっしゃる意味は大体分かりました。

> これはメリットと同格であるデメリットに該当しないと考えています。
> メリットを享受するうえでの、「制限」もしくは「注意事項」といったものでしょうか。

そういう考え方もありますね。
mainが呼ばれた以降は、mainから抜けたりexitが呼ばれるまでは、どこからでもアクセスできるわけですから、許容できる制限だといえばそのとおりです。

> #だた、これは「変数」じゃなくて「定数」ですよね。

私は普段「変数」というあいまいな用語はほとんど使わないのですが、今回は一般的になじみのある「グローバル変数」という用語を使ってみました。実際にはオブジェクトのことです。
ちなみに、「定数」というのは、123とか'A'とか列挙定数のようなものを指します。拡大解釈しても、定数式の一部になりうるものだと思いますので、左辺値であるconst修飾されたオブジェクトは言語仕様上定数とは呼ばないと思います。

> あれ?重要な変数だからこそ、どこからでも(という言葉を付けてさせてください^^;)
> 書き換えが簡単に行えることはデメリットだと思うのですが。

グローバル変数の定義が、「プログラム全体に渡って重要な変数」とのことでしたので、重要かどうかと書き換えが簡単かどうかは直結しないのでは? と考えました。
例えば、書き換えを行うには何重かの鍵を開かなければ例外が出るようなクラス設計もできますから。

たかぎ

Re:【雑談】グローバル変数について

#20

投稿記事 by たかぎ » 14年前

私の意見も書いておきます。
特に指定がなければ、CとC++に共通です。

> 1. グローバル変数とは何か?

非局所オブジェクトのうち外部結合を持つもの。
C++の場合は、さらにprotectedやprivateの静的データメンバでないもの。

> 2. グローバル変数のメリット

目的により、ふたつあると思います。

1) プログラムのどこからでも気軽にアクセスできる。
  → 言い換えれば、気軽にアクセスしてまずいものはグローバル変数にすべきではない。
2) 翻訳単位間で共通に使用する静的オブジェクトに対して効率よくアクセスできる(Cの場合)。
  → 本来であればアクセス可能な範囲を制限すべきだが、言語仕様上無理なので必要悪として存在する。

> 3. グローバル変数のデメリット

1) スレッドセーフにするのが困難、または面倒。
2) 管理上の手間が発生する。

> 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?

検討する順番を書きます。

1) 辞めてもらう。
2) 教育する。
3) 責任範囲が明確になるような設計を行う。
  → 例えば、そのプログラマが担当するプロセスを分離してしまえば、影響範囲は最小限に抑えられます。
4) レビューで何とかする。
画像

lriki

Re:【雑談】グローバル変数について

#21

投稿記事 by lriki » 14年前

>> 1. グローバル変数とは何か?
>> クラスのインスタンス置き場。

>これって記憶域の話では?

インスタンスを格納しておく変数をグローバルに置いておくっていう意味です。
私はそのためにしかグローバル変数は使わないので、こんな風に書いてしまいました。わかりにくい表現で申し訳ありません。


>> 2. グローバル変数のメリット
>> 使いたいときにアクセスできる。

>C++だとそうはいかないのでは?

確かに、未初期化のインスタンスを別の場所で参照することはあり得ますね。
私は普通、コンストラクタとは別に initialize() という関数を作って main に入り次第、順に初期化していくという方法をとっているので、
初期化の順番で問題が発生したことはありません。

この辺は経験不足っていえば経験不足ですが…。
initialize() を作ることで、「main に入ったときに初期化が済んでいる」っていうことを殺してるわけですから、
このあたりは自分でも完璧に納得できていない部分はあります。



>> 3. グローバル変数のデメリット

> これはグローバル変数の問題とは違う気がするのですが、いかがでしょうか?

すいません。開発中に実際に起こってしまって特定にとても苦労したため、苦労自慢のような気持ちで書いてしまいました。
考えてみればグローバルでもクラスのメンバでも普通に起こりますよね。



>> 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
>> 私の場合は「さわらないで」っていうのが第一です。

>これはグローバル変数がすでに存在していることが前提ですか?
>新規に作ることについてはどうでしょうか?

そうですね。
新規に作る場合は、そのプログラマが C++ に触れているのであれば名前空間を使わせてみます。
無理みたいであれば、罰ゲームじゃないですけど自分の名前。
まだ不安があれば、自分の方で名前空間使うなりして対応します。

どのみち何かしらのコストが付いてくるので、やっぱり「とりあえず使うな」が無難だと思います。

ふと、グローバル変数を使わせないでプログラムを書かせるのも、
そのひとにとっては勉強になるんじゃないかなとか考えました。


>> ほんとに何が起こるか分からない場合、

>何が起こるか管理されていないことの方が問題のように思いますが、どうなのでしょうか?

「人間はできることはする」っていう考えから、徹底的に予防しておきたいときってことです。
(すいません。ちょっと文系よりなので言い回しがあやふやになってました…。)



あと、私が普段プログラムで作っているのはほとんどゲームなので、速度重視の点から意見をひとつ。

参照するものを関数やクラスで保護した場合、それが処理速度に影響する場合は直接グローバル変数にします。

たとえば、大量の敵が自キャラと当たり判定を行う場合です。(龍神録のような弾幕なども)
C++ はインライン関数使って高速化できるとありますが、ホントに速度が必要な場合はまだ足りません。
(現場のゲームプログラマは、速度が必要な時はアセンブリを使ってる話も聞きますし)

「低スペ対応!!」という声もよく聞こえてくるので、ちょっと荒い使い方ですけどこんな風にも使ってますよということで書かせていただきました。

このへんはちょっとだけぽこさんの意見に乗るところがあるかもしれません。

たかぎ

Re:【雑談】グローバル変数について

#22

投稿記事 by たかぎ » 14年前

りゅんさん

> インスタンスを格納しておく変数をグローバルに置いておくっていう意味です。
> 私はそのためにしかグローバル変数は使わないので、こんな風に書いてしまいました。わかりにくい表現で申し訳ありません。

文字通りに解釈すると...

union
{
char b[sizeof(foo)];
long aligner; // 境界調整用
} storage; // グローバル変数

int main()
{
foo* p = new((void*)storage.b) foo;
...
p->~foo();
}

のような使い方ということになると思いますが、たぶん違いますよね。

> 確かに、未初期化のインスタンスを別の場所で参照することはあり得ますね。
> 私は普通、コンストラクタとは別に initialize() という関数を作って main に入り次第、順に初期化していくという方法をとっているので、
> 初期化の順番で問題が発生したことはありません。

これをやってしまうと、未初期化のオブジェクトができてしまったり、二重初期化の問題が生じます。
例外処理が使えないような処理系なら仕方ないでしょうが...

> 新規に作る場合は、そのプログラマが C++ に触れているのであれば名前空間を使わせてみます。
> 無理みたいであれば、罰ゲームじゃないですけど自分の名前。
> まだ不安があれば、自分の方で名前空間使うなりして対応します。

名前空間を使わせても、何も問題の解決にならないのでは?
むしろ検索しにくくなるだけのような気がします。
自分の名前のほうがまだましかも。

> 「人間はできることはする」っていう考えから、徹底的に予防しておきたいときってことです。

ということは、最初にDixqさんへの返事で書いたように、関数を介して静的変数へのポインタを返すような脱法行為も想定しないといけませんよね。
もっと極端なことをいえば、アドレスを直接指定してどこからでも使える記憶域を確保されることも想定しないといけないのではないでしょうか?

> 参照するものを関数やクラスで保護した場合、それが処理速度に影響する場合は直接グローバル変数にします。

priavateな静的データメンバであれば、処理速度に関してはグローバル変数と何も変わりませんが、あえてグローバル変数とする理由はあるのでしょうか?

> (現場のゲームプログラマは、速度が必要な時はアセンブリを使ってる話も聞きますし)

状況にもよりますが、これはグローバル変数かどうかとはあまり関係ありませんね。


否定的なことばかり書いているようですが、悪意はありません。
突き詰めた意見交換ができればと考えています。
これはほかの方にもいえます。

へろりくしょん

Re:【雑談】グローバル変数について

#23

投稿記事 by へろりくしょん » 14年前

C++はよく分かりませんので、Cについてです。

>1. グローバル変数とは何か?

非局所変数の事(内部結合含む)
内部結合の場合は、その翻訳単位内でのみ利用される(翻訳単位内でしか利用できない、ではなく)変数。
ニュアンスの違いというか、気の持ちようと言うか、微妙な言い回しですが、分かっていただけるでしょうか。


>2. グローバル変数のメリット

内部結合の場合は、翻訳単位内に限定されるものの、基本的にどこからでもアクセス出来る事。


>3. グローバル変数のデメリット

内部結合の場合は、翻訳単位内に限定されるものの、基本的にどこからでもアクセス出来る事。
基本的にスレッドセーフではない。
スパゲッティ化しやすい。
ちなみに、const オブジェクトについては、スレッドセーフではない事を除いて特にデメリットがあるとは思いません。


>4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?

ルールで縛ります。

たかぎ

Re:【雑談】グローバル変数について

#24

投稿記事 by たかぎ » 14年前

へろりさん、コメントありがとうございます。

> 内部結合の場合は、その翻訳単位内でのみ利用される(翻訳単位内でしか利用できない、ではなく)変数。
> ニュアンスの違いというか、気の持ちようと言うか、微妙な言い回しですが、分かっていただけるでしょうか。

すみません。よくわかりません。
内部結合の場合、変数名でアクセスできるのは同じ翻訳単位内に限定されますね。
けれども、ポインタを介してであれば、どこからでもアクセス可能になります。
その意味で、どこからでもアクセスできるけれども、ルール的にそれを許さないということでしょうか?

> >2. グローバル変数のメリット
> 内部結合の場合は、翻訳単位内に限定されるものの、基本的にどこからでもアクセス出来る事。

これは多くの意見と同じですね。

> >3. グローバル変数のデメリット
> 内部結合の場合は、翻訳単位内に限定されるものの、基本的にどこからでもアクセス出来る事。
> 基本的にスレッドセーフではない。

こちらもそうだと思います。

> スパゲッティ化しやすい。

スパゲッティコードは関数を使っても書けてしまうので、必ずしもグローバル変数に限った話ではないのでは?

> ちなみに、const オブジェクトについては、スレッドセーフではない事を除いて特にデメリットがあるとは思いません。

Cに限れば、constオブジェクトはスレッドセーフだと思うのですが、違う状況があるのでしょうか?

> >4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
> ルールで縛ります。

具体的にどんなルールかを教えていただけると幸いです。

一般的な名前

Re:【雑談】グローバル変数について

#25

投稿記事 by 一般的な名前 » 14年前

この質問目的が不明

未来のプログラマー

Re:【雑談】グローバル変数について

#26

投稿記事 by 未来のプログラマー » 14年前

>へろりさん
スパゲッティ化でメリットってあるんでしょうか
スパゲッティって見にくいってことでは?

lriki

Re:【雑談】グローバル変数について

#27

投稿記事 by lriki » 14年前

>これをやってしまうと、未初期化のオブジェクトができてしまったり、二重初期化の問題が生じます。

シングルトン…って考えてましたけど、シングルトンはグローバル変数ではないですから、今回の話とはまた別のことですよね…。

すいません。おっしゃる通りです。 変なこと言っちゃいました… すいませぬ…すいませぬ……orz



>priavateな静的データメンバであれば、処理速度に関してはグローバル変数と何も変わりませんが、あえてグローバル変数とする理由はあるのでしょうか?

priavate な静的データメンバはアクセスするために関数をひとつ通す必要があるので、
ループを何千も回してそのたびに関数を呼び出しているところには「ちょっと…」って思ってしまうところがあります。

あと、priavate な静的データメンバも frend class を使えば直接アクセスできますが、
必要になるたびにヘッダーに手を加える点にもちょっと疑問があります。

私がこのようなものをグローバル変数とするのは、リスクを冒しても得るものが大きい場合があることと、
メンバーのスキルに不安がない場合、使った方が可読性が上がる場合です。

あと、個人的には「グローバルには唯一となるクラスのインスタンスを置く」っていう考えでプログラムを組んでます。
理由は、そんな風に役目を区切るとスッキリするから…です。



>名前空間を使わせても、何も問題の解決にならないのでは?

ちょっと前に素人さん数人とプロジェクトを組んで制作したことがありました。
メンバーはみんなC++は素人で、とりあえず cout が使えるよ程度の知識でした。
制作にあたって、私がプログラムリーダーということで、メンバーにDirectXの使い方を教えることになりました。
その時、
「みんなまだクラスもちゃんと作れないから、メンバ変数にデバイスのポインタ持っておくとかできないだろうなー…。
 グローバルに書くだろうなぁ…。」
と考えたので、名前空間なら教えるのに時間かからないし(私も自分の担当があったので)、実験半分で使ってみることにしました。

出来上がったコードを見てみると、案の定グローバル変数だらけ。g_D3DDevice とか人数分同名の変数が定義されている始末でした。
ですが、名前空間で区切っていたため他への影響はなく、スムーズに結合できました。

ほんの一例ですが、参考になれば幸いです。




…なんていうか、たかぎさんの気迫に圧倒されてました。ココまで真剣にグローバル変数について考えてるとは……。

同人とか学校の課題とかそんなレベルの意見で首突っ込んで申し訳ないです気分です…orz
もしかして、ここにいる方で学生なのって私だけ……?

Dixq (管理人)

Re:【雑談】グローバル変数について

#28

投稿記事 by Dixq (管理人) » 14年前

> その関数の設計者が知らない方法で初期化される方が危険ではないでしょうか?

そうですね~、設計者が初期化すべき値は初期化の方法を設けていないといけないという事ですね。

> シングルトンだと、同じ型のオブジェクトを複数作れませんよね。

そうですね。

>ただ、書かれているように、その方法では多重化ができませんね。

そうですね~、多重化させたい時はやはり引数で持たせる他無いんですかね・・。

へろりくしょん

Re:【雑談】グローバル変数について

#29

投稿記事 by へろりくしょん » 14年前

>たかぎさん

>けれども、ポインタを介してであれば、どこからでもアクセス可能になります。
>その意味で、どこからでもアクセスできるけれども、ルール的にそれを許さないということでしょうか?

いえ、翻訳単位でしか利用”できない”というネガティブな意味合いで無く、翻訳単位内でのみ使われる事を大前提とする、と、明示する。 という意味で言いましたが、どうでしょうか。
あらゆる言語の中で日本語がもっとも得意なのですが、うまく伝えられません。
基本的に、グローバル変数は”どこからでも”利用可能な変数だと思っています。


>スパゲッティコードは関数を使っても書けてしまうので、必ずしもグローバル変数に限った話ではないのでは?

確かにグローバル変数に限った話ではありませんが、グローバル変数の存在はコードをスパゲッティ化する重大な要因の一つだと考えます。


>Cに限れば、constオブジェクトはスレッドセーフだと思うのですが、違う状況があるのでしょうか?

グローバル変数がポインタだったりする場合、必ずしもそうだとは言えないのでは。
const char *const hoge; みたいに、がんじがらめにしてしまえば、スレッドセーフになるでしょうけども。


>具体的にどんなルールかを教えていただけると幸いです。

内部結合のグローバル変数のポインタを翻訳単位の外に出すの禁止。 とか。
関数内の static な変数のポインタを関数の外に出すの禁止。 とか。




> 未来のプログラマーさん

>スパゲッティ化でメリットってあるんでしょうか

デメリットの1つとしてあげていますよ。

たかぎ

Re:【雑談】グローバル変数について

#30

投稿記事 by たかぎ » 14年前

りゅんさん

> priavate な静的データメンバはアクセスするために関数をひとつ通す必要があるので、
> ループを何千も回してそのたびに関数を呼び出しているところには「ちょっと…」って思ってしまうところがあります。

privateな静的データメンバであっても、同じクラスのメンバ関数からなら直接アクセスできます。
タイムクリティカルな処理を同じクラスに集めればそれで済むと思うのですが、いかがでしょうか?

> あと、個人的には「グローバルには唯一となるクラスのインスタンスを置く」っていう考えでプログラムを組んでます。

この意味がよく分かりませんでした。
「唯一となる」は「クラス」にかかりますか? それとも「インスタンス」にかかりますか?

> 出来上がったコードを見てみると、案の定グローバル変数だらけ。g_D3DDevice とか人数分同名の変数が定義されている始末でした。
ですが、名前空間で区切っていたため他への影響はなく、スムーズに結合できました。

これはちょっと無理があるような...
下手に名前空間を使わせると、きっとADL絡みとかでバグを作ってしまう気がします。
それに、他のプログラマが定義した名前空間をusingで取り込むことを覚えられると、さらに話がややこしくなります。

> …なんていうか、たかぎさんの気迫に圧倒されてました。ココまで真剣にグローバル変数について考えてるとは……。

まあ、職業柄ですね。

たかぎ

Re:【雑談】グローバル変数について

#31

投稿記事 by たかぎ » 14年前

へろりさん

> いえ、翻訳単位でしか利用”できない”というネガティブな意味合いで無く、翻訳単位内でのみ使われる事を大前提とする、と、明示する。 という意味で言いましたが、どうでしょうか。
> あらゆる言語の中で日本語がもっとも得意なのですが、うまく伝えられません。

大体分かりました。

> 基本的に、グローバル変数は”どこからでも”利用可能な変数だと思っています。

だとすると、内部結合の場合はグローバル変数に該当しないと思うのですが...

> >Cに限れば、constオブジェクトはスレッドセーフだと思うのですが、違う状況があるのでしょうか?
> グローバル変数がポインタだったりする場合、必ずしもそうだとは言えないのでは。
> const char *const hoge; みたいに、がんじがらめにしてしまえば、スレッドセーフになるでしょうけども。

ポインタの場合でもconst修飾されていればスレッドセーフですよね。
ポインタの参照先がどうであるかは、また別の問題かと思います。

> >具体的にどんなルールかを教えていただけると幸いです。
> 内部結合のグローバル変数のポインタを翻訳単位の外に出すの禁止。 とか。
> 関数内の static な変数のポインタを関数の外に出すの禁止。 とか。

網羅的なルールを作るのは大変そうですね。
りゅんさんが書かれていたように、「人間はできることはする」という前提に立てば、変数自体のポインタを翻訳単位の外に出せなくても、アクセッサのポインタを持ち回ることは禁止されていないとか、脱法はやはり可能になります。
着手時はスキルが低くても、早い段階で中途半端にスキルが上がることは十分あり得ますからね。

たかぎ

Re:【雑談】グローバル変数について

#32

投稿記事 by たかぎ » 14年前

このあたりでいったん解決にしておくことにします。
ご意見はまだ受け付けますので、遠慮なくどうぞ。

たいちう

Re:【雑談】グローバル変数について

#33

投稿記事 by たいちう » 14年前

完全に出遅れてしまいました。C++です。


> 1. グローバル変数とは何か?

明確な定義は言えません。クラスのpublicメンバもそうですが、
機械的にsetterとgetterを付けられただけのprivateメンバもグローバル的に感じます。
Singletonも実態に大差はない上、「グローバル変数==稚拙なもの、
デザインパターン==洗練された素晴らしいもの」と考えている人が多いようで、
同程度かそれ以上に害があると思います。


> 2. グローバル変数のメリット

> オブジェクトを隠蔽せずに、名前をつけ、コードを読む人に知らしめるだけの必要性、必然性があるんです、絶対。
> 無いなら敢えてグローバル変数にする必要はないと考えています。

と、ぽこさんが書いている通り、メッセージでしょう。
通常使ってはいけないグローバル変数をあえて使うほどのメッセージです。
(私はメリットとして上げますが、ぽこさんには定義なのですね。深いな。)

それと一応書いておくと、100行程度までのサンプルプログラム、
且つ、初心者の文法のお手本としないものならば、
どこからでもアクセスできるというメリットを享受できるでしょう。


> 3. グローバル変数のデメリット

コンストラクタの順序がコントロールできない。
さらに、デストラクタの順序がコントロールできない。


> 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?

建前上は教育とレビューとテスト。
本音としては、、、書くまでもないでしょう。
現実的にも教育とレビューとテスト。成長の期待値と私の焦り具合で優しさ/厳しさが変わります。

『Joel on Software』に書かれていたことを思い出したので、リンクを貼っておきます。
「下っ端でも何かを成し遂げる方法」戦略 4 間抜けを無力化する
http://local.joelonsoftware.com/wiki/%E ... 9%E6%B3%95


# Singletonのガイドラインについても聞きたいな。

Poco

Re:【雑談】グローバル変数について

#34

投稿記事 by Poco » 14年前

> ちなみに、「定数」というのは、123とか'A'とか列挙定数のようなものを指します。拡大解釈しても、定数式の一部になりうるものだと思いますので、左辺値であるconst修飾されたオブジェクトは言語仕様上定数とは呼ばないと思います。

なるほど、勉強になります。

> グローバル変数の定義が、「プログラム全体に渡って重要な変数」とのことでしたので、重要かどうかと書き換えが簡単かどうかは直結しないのでは? と考えました。
> 例えば、書き換えを行うには何重かの鍵を開かなければ例外が出るようなクラス設計もできますから。

確かにC++だとアクセスにフックをかける仕組みが記述できますね。
#Cだと難しい、というか規律で縛る必要がありますね。

なんと言うべきか、、私はプログラムを追う上で一番苦労するのは、変数を追うことだと思います。
ある変数が影響を真面目に調べようとすると、
 ・名前で検索
  ・参照やポインタでエイリアスを作られていたら、それも検索
  ・関数やオブジェクトに渡さてていたら、それも検索
という手順を踏みます。
この作業が一番大変なのがグローバル変数なのかな、と。

ここまで書いて、「書き換えが簡単」なのがデメリットではなくて、「どこからでもアクセスされちゃう」のが
デメリットのような気がしてきました。
#追跡可能性(トレーサビリティ)の観点というべきか、メンテナンス性の観点というべきか。

プログラムを書く上でのメリットがプログラムを読む上でのデメリットになっている、が
私の結論ですかね。

#受け答えになってなくてすみません。
#自分の論理を見つめ直すってのは、面白いですね~。

たかぎ

Re:【雑談】グローバル変数について

#35

投稿記事 by たかぎ » 14年前

たいちうさん

> > 1. グローバル変数とは何か?
> 明確な定義は言えません。クラスのpublicメンバもそうですが、
> 機械的にsetterとgetterを付けられただけのprivateメンバもグローバル的に感じます。

メンバ関数の場合は、オブジェクト自体が局所的であればグローバル的とはいえないのではないでしょうか?
もちろん、非局所オブジェクトに対して機械的なアクセッサを設けた場合には、グローバル変数と大差ありませんね。
まあ、オブジェクト自体のポインタや参照を取得されないのであれば多少はましという考え方もありますが、アクセッサのポインタを持ち回ることはできますので、やはり大差ないと思います。

> Singletonも実態に大差はない上、「グローバル変数==稚拙なもの、
> デザインパターン==洗練された素晴らしいもの」と考えている人が多いようで、
> 同程度かそれ以上に害があると思います。

シングルトンとグローバル変数とはまったく別の概念なのでは?
特定の有効範囲や翻訳単位からしかアクセスできないシングルトンがあってもよいわけですから。

> > 3. グローバル変数のデメリット
> コンストラクタの順序がコントロールできない。
> さらに、デストラクタの順序がコントロールできない。

翻訳単位にまたがるとそうなりますね。
ただ、これだと、mainの最初の文から最後の文(またはexitが呼ばれる)までしかグローバル変数にアクセスしないのであれば、デメリットがないということになるかと思います。
そういう認識でよろしいでしょうか?

> > 4. 開発メンバにスキルが低いプログラマがいる場合はどうすべきか?
> 建前上は教育とレビューとテスト。
> 本音としては、、、書くまでもないでしょう。
> 現実的にも教育とレビューとテスト。成長の期待値と私の焦り具合で優しさ/厳しさが変わります。

まあ、そうでしょうね。
私のように人事権があれば、別の方法が取れますけど...

> 「下っ端でも何かを成し遂げる方法」戦略 4 間抜けを無力化する

技術的には解決になるかもしれませんが、コスト面の問題はあるので、私の立場ではなかなか採用しづらい方法です。

> # Singletonのガイドラインについても聞きたいな。

また、別の機会に。
何なら、雑談スレを立ち上げてください。

たかぎ

Re:【雑談】グローバル変数について

#36

投稿記事 by たかぎ » 14年前

ぽこさん

> なんと言うべきか、、私はプログラムを追う上で一番苦労するのは、変数を追うことだと思います。
> ある変数が影響を真面目に調べようとすると、
>  ・名前で検索
>   ・参照やポインタでエイリアスを作られていたら、それも検索
>   ・関数やオブジェクトに渡さてていたら、それも検索
> という手順を踏みます。
> この作業が一番大変なのがグローバル変数なのかな、と。

これについては同感です。
実際には上記に加えて、パイプ等のストリームやメッセージの類いでポインタが持ち回られる可能性がありますし、コンテナに格納されたり、最悪の場合は構造体のメンバに格納されて、オフセットでアクセスされたり、テンポラリファイルに格納されたりといったこともあり得ます。
しかも、これはグローバル変数に限った話ではなく、アクセッサやグローバルな設定関数も関数へのポインタを持ち回れるので同じことがいえます。

> ここまで書いて、「書き換えが簡単」なのがデメリットではなくて、「どこからでもアクセスされちゃう」のが
> デメリットのような気がしてきました。
> #追跡可能性(トレーサビリティ)の観点というべきか、メンテナンス性の観点というべきか。

これが本質でしょうね。

閉鎖

“C言語何でも質問掲示板” へ戻る