
以前にC++の講義を受けた際に
for(int i = 0; i < hoge ; i++){
int j;
・
・
・
}
のようなコードを書くと、jがhoge分だけ"生成されて
しまう"のでよろしくありません。と教えられました。
しかし、最近別の方からこの部分に関しては、jをfor文の
中に定義しようが、最適化?によりfor文の外に出された
バイナリが生成されると聞きました。そのため、jが
必要となる直前でjを定義しても(for文の中に定義しても)
問題ない。と教えられました。
どちらが正しいのでしょうか?
近年にC++の仕様変更があったとしたら、それに伴い
変更されたのでしょうか?
また、どのようなコードが望ましいなどありましたら
教えてください。
A 回答 (6件)
- 最新から表示
- 回答順に表示
No.6
- 回答日時:
「j が hoge 分だけ生成される」というのはちょっと語弊はあるけど, 「j が hoge 回生成される」という意味ならその通り. ただし, 「同時に hoge 個存在する」ということはあり得ないし, それが「良くない」かどうかは別の話. だいたい, これが「良くない」なら「(main 以外の) 関数内部のローカル変数」や「関数の引数」も「良くない」ことになってしまう.
で, プログラミングのスタイルとしては「変数のライフタイムはなるべく短くする」というのを原則にしていいと思います.
だから, 「for の 1回の繰り返しで生きていればいい (各繰り返しごとに違う変数と思う)」なら for の中で定義することになるし, 「1回の繰り返しを超えて値を保持しなければならない」なら for の前で定義することになります (というかそうするしかない).
いずれにせよ「プログラムの通りに動作しているように見えればコンパイラがどのように変えても問題ない」ので, この点について仕様の変更はないはずです.
おまけですが, 変数の定義をループ本体に入れた場合, この仕様からコンパイラがどう最適化しても「複数回生成される, ように見える」必要はあります. int だと大して問題ないけど, コンストラクタ (とデストラクタ) をもつクラスでは毎回コンストラクタ/デストラクタを呼び指すことになります.
No.5
- 回答日時:
まずは、そんなアホな事を教えている先生を首に・・・
は、おいておいて
プログラミングの基本で説明しておきます
A.int j;
for (i=0; i<hoge; i++) {
.
.
}
というのと
B.for (i=0; i<hoge; i++) {
int j;
.
.
}
というのはプロからみた場合圧倒的に意味が異なります
Aの場合は「このfor以降でjを使用する部分があるので、注意せよ」というのを暗に示しているし(だからjなんて変数名つけるのはバカ)
Bの場合は「このループの中で一時的に使用しているワーク変数なので、あんまり気にしなくていい」というのが裏にあります
プログラムを「動けばいい」なんて教えている人がいますが、私は間違っていると思います
「美しく、読みやすい」のが最高と思います
No.4
- 回答日時:
> for(int i = 0; i < hoge ; i++){
> int j;
> ・
> ・
> ・
> }
> のようなコードを書くと、jがhoge分だけ"生成されて
> しまう"のでよろしくありません。と教えられました。
この例の場合、jは"複数個"生成されるわけではありません。
ただし、この場合において(明示的に)最適化をまったく行わない設定でコンパイルすると、
ループの終了時に変数jが破棄され、(結果として)同じメモリ位置に再度変数jが設定されることになるでしょう。
当然、このコードでは変数jは初期化されていませんので、(再度設定された)変数jの値は直前にループ終了時に入っていた値が
入っているはずです。
また、この(最適化しない)場合では、ループが終了しない(=継続する)場合、破棄した変数を直後に(同じ位置に)設定するという
(それ自体にあまり意味のない)処理が起こりうることになります。
つまり、"複数回"生成される、という説明に(一応は)嘘はありません。
ただし、これは「最適化をまったく行わない」ケースにおいてのみです。
実際には最小限の最適化を行うことがふつうです。
ですから
> 最近別の方からこの部分に関しては、jをfor文の中に
> 定義しようが、最適化?によりfor文の外に出された
> バイナリが生成されると聞きました。
お聞きになった内容というのは、つまりコンパイラによる最適化によって、先のコードは
{
int j; //←変数を設定する
for(int i = 0; i < hoge ; i++){
・
・
・
} //←ここでは変数を破棄しない
} //←ここで変数をスタックから破棄する
こう書いても同じ機械語コードが生成されることになるはずだという意味です。
当然
for(int i = 0; i < hoge ; i++){
int j=1; //←変数を設定すると同時に初期化
・
・
・
} //←変数を破棄する
こうなっている(変数を初期化している)場合は
{
int j; //←変数を設定する
for(int i = 0; i < hoge ; i++){
j=1; //←初期化
・
・
・
} //←ここでは変数を破棄しない
} //←ここで変数を破棄する
こうなるであろうことは容易に想像できます。
> どちらが正しいのでしょうか?
上記の理由により、「どちらも正しいが、前提条件が違うため比較することに意味がない」といえるでしょう。
もっと突っ込んでいうと、最適化をまったく行わないコンパイラは通常存在しないため、
「複数回生成される」という説明のほうが「非現実的」であるといえるでしょう。
> また、どのようなコードが望ましいなどありましたら教えてください。
この点については、あなたが理解しやすいコードであるべきです。
現在のコンパイラの最適化機能は大変優れています。
コーディングに多少工夫を凝らしたところで、同じ機械語コードに翻訳されたり、
場合によってはかえって効率の悪いコードが生成されることすらあります。
No.3
- 回答日時:
コンパイラには通称「as if」ルールというのがあります。
これは
「結果が変わらなければ、コンパイラは何をしてもよい」
というものです。
つまり、二人目の方が仰られているように、int j;がforの
外に置かれようが、中に置かれようが、結果が変わらなければ
コンパイラはどっちに置いても良い。ということになります。
スタックにintを置くコストが多少はあるので、今回のような
場合は、forの外に出して「最適化」をコンパイラが"してもいい"
ということになります。
さて、どのようなコードが望ましいかについてですが、
「一般的にfor文中に入れたほうが良い」ということになっています。
これは、Code Completeの上巻で述べられていることなのですが、
変数のBindTime(変数を変化させられる時間)は「実際に利用する時間」
に近ければ近いほど良い、つまりfor文の中でしかint j;を利用しない
のであればそれより大きいスコープ(for文の外)には置くべきではない
ということになっています。
(そして私もそう思います)
ご回答ありがとうございます。
基本型については、for文の中に入れても
問題なさそうですが、クラス変数については、
場合によってはfor文の外に宣言したほうがいいのかな・・
と思いました。(後番の回答者さんが記述されているように、
コンストラクタとデストラクタがfor文の1回に実行中に
1回づつコールされてしまうため)
No.2
- 回答日時:
>のようなコードを書くと、jがhoge分だけ"生成されて
そんなアホなコンパイラはこの世にありません。
自動変数の自動を動的生成と勘違いしたのでしょう。
自動変数の自動は関数が呼ばれたときに自動的にスタック上に作られる、
ということで関数が呼ばれなければ作られません。
Cも同様。
簡単な関数のアセンブラ出力を眺めれば一目瞭然かと。
ただし、
この世にはスタックの無いコンビューター IBM360系等もありまして、
その場合は動的生成ですね。たぶん。でもうまくやってるでしょう。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# LU分解法のピボット選択機能実装について(C言語・gcc-9) 1 2022/07/22 15:20
- C言語・C++・C# LU分解法のピボッティングについて(C言語/gcc-9) 3 2022/07/11 23:10
- C言語・C++・C# 変数のスコープ 5 2023/05/27 17:50
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- Visual Basic(VBA) 前回ご教授いただいたコードに覚えたてのループ処理で品名りんごAから順に20回for nextでループ 7 2023/01/13 22:01
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
unsigned long long 型のフォー...
-
EXEファイルにランタイムは必要?
-
ソフトの開発言語を調べる方法
-
フォートランの初歩でつまって...
-
for文内での変数定義
-
AIXとCOBOLについて
-
Win32のIME制御について
-
COBOLの論理演算子について質問...
-
WIZ-Cの使い方について
-
COBOL計算式の中間ワーク桁数に...
-
FORTRANのおすすめコンパイラ
-
変数の内容がコロコロ変わる、...
-
リリースモードとデバッグモー...
-
python エラー
-
エクセルのエラーメッセージ「4...
-
<unistd.h>をVisualStudioでつ...
-
” OS ビルド ” の意味が分か...
-
eclipseでデバックするとエラー...
-
Eclipseのブレークポイントが○...
-
VBAを何回も作り直して、容量が...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ソフトの開発言語を調べる方法
-
unsigned long long 型のフォー...
-
C++でデスクトップGUIアプリ開...
-
COBOLの論理演算子について質問...
-
組み込みソフト。ROM領域にデータ
-
printfなど、標準関数のソース...
-
cc と gcc の違い
-
リリースモードとデバッグモー...
-
パーサとコンパイラの違いって?
-
AIXとCOBOLについて
-
<conio.h>?
-
COBOLのALPHABET...
-
VC++の/Zm オプションについて
-
C++Builder → Visual C++ 移植...
-
C言語の規格
-
COBOLの論理演算子について
-
変数の内容がコロコロ変わる、...
-
Macで使えるC言語のコンパイラ...
-
PICでのI2C通信でのマスタ、ス...
-
最初に使う変数のゼロクリアに...
おすすめ情報