今日の呟き

for文の[前置++ 後置++]

アバター
V30
記事: 21
登録日時: 10年前
住所: 岡山県

for文の[前置++ 後置++]

投稿記事 by V30 » 7年前

アセンブリ出力してみたら、どっちも同じだった。
[条件:VS2017・int型変数使用時]

C++コード(全部)
► スポイラーを表示
アセンブリ出力(一部)
► スポイラーを表示
コンパイラ依存だと思われるので、異義と言い切るのは危険!
もちろん、同義とも言い切れない。
しかし、VS2017既定の設定でコンパイルすれば、同義だ。

そもそも operator++ の前置・後置は、評価前・評価後のどっちに
インクリメントするかのお話なので、for文の ++ みたいに評価され
ない場合は、単にインクリメントするだけみたいだ。


では、int型と同様に働く自作のCintクラスを使用した場合は、どう
なるのか?
こんな場面は多分ないだろうけど、調べたい人はご自身でどうぞ。


何れにしても、過去に誰か書いていそうな案件だ。
オフトピック
今更かも知れないけど、インクリメント命令ってなくなってんの?
最後に編集したユーザー V30 on 2017年12月16日(土) 08:14 [ 編集 1 回目 ]

25130
記事: 4
登録日時: 7年前

Re: for文の[前置++ 後置++]

投稿記事 by 25130 » 7年前

推測で申し訳ありませんが,
自作クラスであり、かつ最適化無効(-O0や/Od等)の場合,
前置インクリメントの方が早くなりそうです。

理由としては、クラスを使用する際,
前置インクリメントのオーバーロード定義は

CODE:

Class&  operator++();
であり、参照を返すのに対し,

後置インクリメントのオーバーロード定義は

CODE:

Class operator++(int);
であり、コピーを返します。

つまり、メソッドの内容を全く考慮しない状況(最適化無効がこれにあたる?)でのコンパイルが行われた場合,
毎回コピーを作るアセンブリ(?)が生成されるかと思います。

アバター
V30
記事: 21
登録日時: 10年前
住所: 岡山県

Re: for文の[前置++ 後置++]

投稿記事 by V30 » 7年前

25130 さん

クラスを使う場合は、コンパイラの設定次第でまともに
動くかどうかも決まりそうですね。

掲載コード内自作クラスの場合は、コンパイラ既定の設定で
オーバーロード問題は解決しています。
作った方の operator++ が呼ばれるようになっています。
VS2017コンパイラ、あったまいいね!

c++既定の整数型変数を使う分には、前でも後でも良さげです。
前置が当たり前みたいな風潮になっているのは、最適化とか
実際の出力とかを無視しているようで、ちょっと調べてみた
次第です。

25130
記事: 4
登録日時: 7年前

Re: for文の[前置++ 後置++]

投稿記事 by 25130 » 7年前

V30 さんが書きました: 作った方の operator++ が呼ばれるようになっています。
定義された方のoperatorが使用方法に応じて自動的に選択されると解釈し,
前置インクリメントのみオーバーロードした状態で後置インクリメントを試してみましたが,
コンパイルエラー(C2676)になりました…

コード

CODE:

struct A {
	A& operator++() { return *this; }
};
void main() {
  A a;
  a++;
}
環境
Visual Studio 2017 15.3.5
(コンパイラバージョン: 191125506)
最後に編集したユーザー 25130 on 2017年12月15日(金) 23:27 [ 編集 1 回目 ]

アバター
V30
記事: 21
登録日時: 10年前
住所: 岡山県

Re: for文の[前置++ 後置++]

投稿記事 by V30 » 7年前

実行してみてチョイと間違いがあったので、訂正。
・後置++の戻り値の型→ & を取りました。よくやるミス!
・代入演算子 = →使わないので、丸ごと消去。


>25130 さん

作らなければ、エラーになるってことですね。勉強になりました。
+1オーバーロードを、既定のがあるのかと勘違いしていました。
自分が作ったもう一方の++演算子の事のようです(汗)

そもそも、21530さんがおっしゃるクラスの(既定?) operator++ って、
無いですね。(要らないから無くしたのでは?)
旧式のC++やコンパイラの細かい仕様には詳しくないし、その辺の事は
今勉強している人は知らなくても問題ないんじゃないかと思います。
参照やコピーは、& や = 使えって事だろうし。
このままでエラー・警告もなく自分の思った通りの挙動を見せている
から、個人的には問題はありません。

for文内の反復子に関しての前置++・後置++話なので、値を格納出来て
値を一定量ずつ増やせて値の 小 < 大 比較ができるクラス以外のfor文
でまともに使えないクラスについては、話が脱線しています。
質問掲示板の返答でもよくある光景ですけどね。

operator についてはまだまだ初心者なので、知らない事はどんどん
勉強して行きたい気持ちはあります。

アバター
purin52002
記事: 235
登録日時: 8年前

Re: for文の[前置++ 後置++]

投稿記事 by purin52002 » 7年前

これは「i++より++iの方が早い(どやぁ)」と言えなくなりそうですね^^;

ちょっと調べてみたところint型のインクリメントはアセンブルすれば後置でも前置でも出力は同じっぽいですね。
ただ自作クラスの場合で、ソースファイルがわかれている場合は
(main.cppでインクリメント、myclass.cppでoperator定義)
若干前置の方が効率がいいらしいです。

インクリメントの大部分がfor文の中のint型変数に対して行われることを考えれば、
前置、後置の差はほぼないですね^^;

アバター
V30
記事: 21
登録日時: 10年前
住所: 岡山県

Re: for文の[前置++ 後置++]

投稿記事 by V30 » 7年前

>Purin52002 さん

後置どやぁ 言ってるわけではなく、常に前置使っておけば、
ちょっとした変化が起きても問題なく対応できるのは確かです。
私みたいなおっちょこちょいなら、尚更です。

C言語から引き継いだ伝統の i++ を今更使うな言われても...
他の言語も同様の事態だろうし...

よしっ!
これからは、なるべく前置使おう。
違和感ありありで、なんか気持ちが進まないけど。。。

ISLe
記事: 2650
登録日時: 14年前

Re: for文の[前置++ 後置++]

投稿記事 by ISLe » 7年前

iがクラスオブジェクトの場合はi++より++iが効率良いですが、無条件にi++より++iが良いみたく言われていると聞いたのは初耳です。
うっかりミスを防ぐために常に++iを使うのが良いふうに言われるのが誤って伝わったのでしょうか。
V30 さんが書きました:そもそも operator++ の前置・後置は、評価前・評価後のどっちに
インクリメントするかのお話なので、for文の ++ みたいに評価され
ない場合は、単にインクリメントするだけみたいだ。
どっちにインクリメントするかではなくて、式(の評価)として
前置インクリメント式は、インクリメントしたあとの値
後置インクリメント式は、インクリメントするまえの値
になるというのが肝ですね。

後置インクリメントの演算子オーバーライドでは、インクリメントするまえの値を返すためにバックアップを作る必要があるので、オブジェクトの生成コストがかかります。

あと提示されたコードの問題点として、Cintクラスのインクリメント演算子のオーバーライドでCintを返さないと、インクリメント式の結果を利用する場合に不都合があります。

以下のコードを見ていただいたら前置より後置のほうにコストがかかるということが一目瞭然かと思います。
► スポイラーを表示

アバター
usao
記事: 1889
登録日時: 12年前

Re: for文の[前置++ 後置++]

投稿記事 by usao » 7年前

operator++なんてあまりにも書く機会が無さすぎて
「引数にint書いてるのがどっちなんだっけ?」ってなる(=必要なときに素で書けない)方がずっと深刻な問題だ.