C++相談室 part132

■ このスレッドは過去ログ倉庫に格納されています
2017/10/10(火) 00:11:34.01ID:nc/5PI4P0
次スレを立てる時は本文の1行目に以下を追加して下さい
!extend:on:vvvvv:1000:512

C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。

前スレ
C++相談室 part131
http://mevius.2ch.net/test/read.cgi/tech/1501295308/

このスレもよろしくね。
【初心者歓迎】C/C++室 Ver.101【環境依存OK】
http://mevius.2ch.net/test/read.cgi/tech/1500329247/

■長いソースを貼るときはここへ。■
 http://codepad.org/
 https://ideone.com/

[C++ FAQ]
https://isocpp.org/wiki/faq/
http://www.bohyoh.com/CandCPP/FAQ/ (日本語)
VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured
2017/11/15(水) 20:48:51.98ID:5RHQ4qAcM
>>711
ありがとう参考にする

しかし、よくこうスラッとプログラム書けるよなぁ
凄いわ
2017/11/15(水) 20:52:44.99ID:r8JgjB1aM
平均なら
https://ideone.com/tZALcZ
で充分と思うが
2017/11/15(水) 22:24:21.73ID:KiQc4/2v0
自分なりにやってみた。
https://ideone.com/ugURi1

>>711
vector::insertで領域の再確保が起こると既存のイテレータが破壊されるんで
24-25行あたりの処理はヤバイ。
2017/11/15(水) 22:45:07.35ID:sivdqd190
>>694
書き方だけならもう少し洗練?できるだろうけど
https://ideone.com/DYlMc0
2017/11/16(木) 19:03:07.86ID:qgvG7lfo0
すれちがいだけど、
C++が出る前のC言語で、STLが必要な処理はどうしてたの?
2017/11/16(木) 19:10:17.36ID:1Qzf60whd
>>716
固定バッファとか、ヒープとか、自己参照構造体などで管理してたはず。
2017/11/16(木) 20:50:27.90ID:WXeeSnzL0
>>612 ←こういう馬鹿がいるから
2017/11/16(木) 21:22:02.83ID:xIkq77qW0
一応つっこみ。
型の一般化がテンプレートと思うが
マクロじゃなくてテンプレート使えって書いてた本もあったような
気がする。
720デフォルトの名無しさん (スップ Sd82-lBnI)
垢版 |
2017/11/16(木) 21:27:58.68ID:w4cxkmV2d
>>718
新たな馬鹿の登場かな?
2017/11/16(木) 21:39:47.71ID:Pxu9bZObM
>>716
いや自分で書けばよくね?
2017/11/17(金) 08:37:40.63ID:smNhjLrp0
>>716
STL 等はあれば便利なだけで「それが必要な処理」などない。
723デフォルトの名無しさん (ワッチョイ 4178-kX9V)
垢版 |
2017/11/17(金) 09:38:50.05ID:S87VOpst0
>>716
STLで使われているアルゴリズムはC++前からあったものばっかだよ
2017/11/17(金) 09:46:53.51ID:4EHSQg4KM
汎用アルゴリズムのコードを業界で共通化することもなく、みんなが各々で実装してたんですか?というアンチテーゼだろ
2017/11/17(金) 09:59:16.63ID:smNhjLrp0
違うと思うけど?
2017/11/17(金) 10:03:14.26ID:NwY4XtJI0
まぁ、ライブラリとして偏在はしてたんだろうけど、あの会社はあのライブラリこの会社はこのライブラリってややこしいことになってたと思う。
2017/11/17(金) 16:57:04.66ID:vGXyPrNqa
リンクリストと平衡二分木ぐらいなら雑に書いても500行ぐらいでできる
みんな大学の復習と思って書いてたんじゃないかな?
2017/11/17(金) 18:49:47.16ID:a6b9gyRQd
自力で書いてる人の方が多かった
STLがあっても用途によっては独自になるよな
ディスク上に作るとか、JPEGのハフマン符号みたいに表現が決まってる物とか
2017/11/17(金) 18:52:08.38ID:a6b9gyRQd
STLはあくまでお手軽用途
表現縛りがなかったとしても、
ガチガチに最適化する用途では使えない
730デフォルトの名無しさん (ワッチョイ 8203-Eq1o)
垢版 |
2017/11/17(金) 20:50:18.49ID:HNipYc2I0
最適化できない? なんで??
テンプレートだろ
731デフォルトの名無しさん (ワッチョイ f9b3-AWKa)
垢版 |
2017/11/17(金) 21:51:52.32ID:Eetf/DNi0
テンプレート万能説爆誕。
2017/11/17(金) 22:21:21.86ID:EgKbzTW+0
if ( オーバーヘッドがない != 最適化される )
2017/11/17(金) 22:36:52.56ID:stAFfC8Ar
ガチガチに最適化する状況が最近はほとんどない
2017/11/17(金) 23:08:51.45ID:grVEZAi9M
ガチガチに最適化すべき場合ってどんな時だろうか
735デフォルトの名無しさん (ワッチョイ f9b3-AWKa)
垢版 |
2017/11/17(金) 23:17:53.86ID:Eetf/DNi0
ガチガチの最適化が仕様に盛り込まれたとき。
2017/11/17(金) 23:46:01.61ID:grVEZAi9M
そんな恒真命題は期待してないゾ

証券取引所とかか
2017/11/17(金) 23:47:03.87ID:Xj6+FFKd0
プログラミング工数の最適化
738デフォルトの名無しさん (ワッチョイ a980-61Vg)
垢版 |
2017/11/17(金) 23:50:29.19ID:sEHgCDk10
最近は凝ったアルゴリズムより単純な配列(vector)の方が速かったりするうえに、余程古いかクソな標準ライブラリを使用してない限りstd::vectorを最適化する余地なんてほぼ無いわな。
2017/11/18(土) 00:03:07.23ID:r8nC/FGp0
最適化はコンパイラに任せてソースは読み易さ重視
std使っとけばデバッガでも追いやすいし
740デフォルトの名無しさん (ワッチョイ f9b3-AWKa)
垢版 |
2017/11/18(土) 00:08:41.90ID:CUoz+hOS0
拡張ライブラリが有ったとしたら、名前空間はstxになるのかね。
741デフォルトの名無しさん (ワッチョイ f9b3-AWKa)
垢版 |
2017/11/18(土) 00:11:29.34ID:CUoz+hOS0
Qtでウェブサイト作ったら何の問題もなくずっと動き続けてびっくりですよ。
Javaスレの人たちがC++は稼働し続けるとメモリーの分断化で落ちるとか言ってたから、
早く書き直さなきゃって思ってたんだけど。
クライアント用のQtがサーバーで頑健だったのは意外だった。
742デフォルトの名無しさん (ワッチョイ 4178-kX9V)
垢版 |
2017/11/18(土) 00:14:32.63ID:asu2qdyg0
まぁ意識高い系が言うことなんかその程度ってこった
2017/11/18(土) 00:21:40.93ID:GO3RY34O0
>>741
TreeFrogの人?
744デフォルトの名無しさん (ワッチョイ a980-61Vg)
垢版 |
2017/11/18(土) 01:10:27.30ID:PnwIkFzo0
>>741
クソJavaプログラマーがC++を書くとほぼ間違いなくやるただのメモリリークを俺のせいじゃないということにしたかっただけというのに1票
745デフォルトの名無しさん (ワッチョイ 25d6-Eq1o)
垢版 |
2017/11/18(土) 06:06:05.59ID:mIICZMYh0
自分のコードでさえ後で読むと読みやすく書いたつもりが裏目に出ていたりする
2017/11/18(土) 08:23:02.49ID:cx1PUhyJ0
奴らはnewしても決してdeleteしないからな
2017/11/18(土) 11:32:01.12ID:azZ7ClyG0
俺も最近unique_ptrに任せっきりでdeleteってほとんど書かねえわ
コピコンの=deleteとかは書くけど
2017/11/18(土) 12:02:10.83ID:Erlsd62p0
>>739
古いコンパイラ(つっても10年くらい)だと、クラス内の配列をイジるとクラスオブジェクト自体がイジられたことになるので最適化放棄とかしてたしなー
そういうのだとvectorなんて最適化放棄しまくり。
2017/11/18(土) 13:45:01.11ID:6KFO0fze0
バカは素直にスマポ使っとけばいいのにな
2017/11/18(土) 14:09:50.22ID:fgAW9Gk/0
>>748
オブジェクトXに対するアクセスの最適化放棄はコンパイラの知りえない形での
Xへの副作用が有り得ると判断された場合に行われるがこれは現用コンパイラでも変わらん
改善したというのはコンパイラの能力向上というよりは、テンプレートによるインライン展開のご利益なのでは…
(つまりstd::vectorは元来最適化向きの進化である
2017/11/18(土) 14:13:16.03ID:fgAW9Gk/0
例:
次のコードの並びにおいて、
1と3の読み込み結果は同一とはみなされず、1〜3を通してのX.aのレジスタ割り当ては行われない
 1. Xのメンバaを読む
 2. 外部リンケージ(かつ素性の知れた組み込み関数以外)の関数foo()を呼ぶ
 3. Xのメンバaを読む

特効薬はfoo()のインライン展開
2017/11/18(土) 14:16:28.52ID:fgAW9Gk/0
なお手動を厭わないなら次の風にしても良い:
 0. auto変数v = X.a
 1. X.aを読む代りにvを読む
 2. 外部リンケージ(かつ素性の知れた組み込み関数以外)の関数foo()を呼ぶ
 3. X.aを読む代りにvを読む

これならいくら古いコンパイラでもvを1〜3を通してレジスタ割り当てすることが気体できる
753デフォルトの名無しさん (ワッチョイ f9b3-GXP8)
垢版 |
2017/11/18(土) 16:28:12.38ID:gZtBhbAH0
浮動小数点をすべて網羅するループが書きたいのですがどうすればいいでしょうか。
754デフォルトの名無しさん (ワッチョイ f9b3-AWKa)
垢版 |
2017/11/18(土) 16:29:45.36ID:CUoz+hOS0
ラスボス級が現れた。
2017/11/18(土) 16:46:32.60ID:gZtBhbAH0
http://takashiijiri.com/study/miscs/fastsqrt.html
やりたいことは、上のサイトにある高速根号計算の精度検証です。

サイト内では2の根号に対して精度検証していますが
すべての倍精度実数に対して検証をしたいと考えています。

64bitの整数のビット表現を、同じビット表現の倍精度実数に変換できれば
整数についてループを回すことで網羅できると考えています。

変換の方法をご存知の方がいれば教えて頂けないでしょうか。
2017/11/18(土) 16:47:50.09ID:R4dFDjUs0
>>753
イプシロン足してくとか。
2017/11/18(土) 16:48:48.90ID:np1Yc2el0
>>755 memcpy
2017/11/18(土) 16:49:32.41ID:R4dFDjUs0
>>755
IEEEの仕様読め。
https://ja.wikipedia.org/wiki/IEEE_754
2017/11/18(土) 16:50:13.11ID:R4dFDjUs0
>>757
reinterpret_castでいい予感。
2017/11/18(土) 16:51:55.15ID:np1Yc2el0
>>755
ところでその検証、何年ぐらい時間かけていい話なの?
2017/11/18(土) 16:53:01.86ID:np1Yc2el0
>>759
未定義動作でも「いい」と言うなら、そう。
2017/11/18(土) 16:55:15.51ID:R4dFDjUs0
あー検証だからな。すまんかった。
2017/11/18(土) 17:20:21.34ID:gZtBhbAH0
みなさま、レスありがとうございます。

>>757
memcpyでできそうです。ありがとうございます。

int main() {
double f = 0;
for (unsigned long long i = 0; i <= -1; ++i) {
void* fp = static_cast<void*>(&f);
void* ip = static_cast<void*>(&i);
std::memcpy(fp, ip, sizeof(i));

std::cout << f << std::endl;
}
system("pause");
}

>>760
そんなに時間かかるんですかね。。。
1週間ぐらいは覚悟してたんですが。
とりあえず回してみます。
2017/11/18(土) 17:32:14.09ID:np1Yc2el0
>>763
https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/
> ... you can test every float bit-pattern (all four billion!) in about ninety seconds. ...

32bit が 90 秒ほどで済ませられるそうな。 64bit だと単純計算で・・・ 735439.6... 年ぐらいかな。
1週間で済ませようと思ったら 38347922 並列ぐらいで走らせればよさそう。

検証する計算内容によっても変わるだろうけど、まぁがんばれ。
2017/11/18(土) 17:35:34.11ID:hpuIg+Nf0
とりあえず範囲を絞って回してみて、
力任せの方法で受け入れられる処理時間なら単純なプログラムのまま、
時間かかりすぎるようなら先にプログラムを洗練させる、としないと。
2017/11/18(土) 17:56:05.12ID:gZtBhbAH0
>>764
ありがとうございます。
32bitと64bitが桁違いですね

範囲を絞ったり、間隔あけてサンプリングしたりしてみます。
2017/11/18(土) 19:06:18.60ID:cx1PUhyJ0
isnan()でnanチェック入れたほうが良さそう
2017/11/18(土) 19:44:12.36ID:euoYf0NO0
>>761
未定義にはならなくね?ポインタtoポインタだからそのまま、で終わりでは。
なお、Cなら

*(long long*)&f = i; // mov命令でコピー
または
f = *(double*)&i; // fmov命令でコピー


>>766
まず仮数部53bit+指数部の偶奇で54bit分でいい。
非正規化数もいらないだろうから仮数部52bit扱いでもいい。
意味が分からないのなら仕様読め>>758
2017/11/18(土) 20:29:47.22ID:np1Yc2el0
>>768
type-based aliasing rule (strict aliasing rule) というものがあってな。
(詳しく調べると闇に落ちるから言語オタクでもなければ深堀りはおすすめしない。)

mempcy なら動作が定義されてるかというとそうでもないんで、
明示的に未定義といわれているかどうか(=最適化で問題を起こしやすいかどうか)の違いしかないんだけど。
2017/11/18(土) 20:40:55.67ID:b6ZSsfqz0
std::launder「そろそろ俺の出番だな」
2017/11/18(土) 21:23:52.47ID:azZ7ClyG0
ここまでfrexpとldexpの話なし
2017/11/18(土) 21:57:24.41ID:QiNK1qRtd
https://github.com/katahiromz/RisohEditor

せっかくだから、だれかバグ発見・修正してけ。
2017/11/18(土) 21:58:52.49ID:QiNK1qRtd
初回の例外というのがよくわからない。。。
774デフォルトの名無しさん (ワッチョイ 4178-kX9V)
垢版 |
2017/11/18(土) 22:06:57.57ID:asu2qdyg0
なんか古い書き方だから2000年ごろからの年季の入ったソースかと思ったら最近の奴なんだな
2017/11/18(土) 22:12:33.66ID:QiNK1qRtd
>>774
古臭い技術専門が時代遅れのために作っているもんだから、古いと言われても仕方ない。
auto、C++11が使えるclang++に移行したい。
2017/11/18(土) 22:42:09.82ID:euoYf0NO0
>>769
調べたけどこれでいいのか?
https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule

これならreinterpret_cast関係ないじゃん。static_castにしたところで変わらん。
ただそれ以前に該当しないだろ。
「同一のメモリを違う型としてaliasしたときにコンパイラがそれに気づけず最適化で削除してしまう」という問題であり、
今回はそうではない。

> mempcy なら動作が定義されてるかというとそうでもないんで
ほんとか?それじゃmemcpyマトモに使えないじゃん。
void*は++で1増えるって仕様に決まったはずで、、、と思ったがこれがgcc拡張だという話があり、このことを言っているのか?

ならグダグダ言わずにCキャストで書けよもう、としか思わないが。
或いはC++的には許せないのかもしれんが static_cast<double>にしてしまうとかか?
2017/11/18(土) 22:48:23.04ID:euoYf0NO0
すまんミスった
× static_cast<double>
○ static_cast<double*>
2017/11/18(土) 23:20:13.09ID:np1Yc2el0
>>776
static_cast じゃコンパイル通らない。

"*(long long*)&f = i" は double 型のオブジェクトに long long 型の参照を通してアクセスしているので
未定義動作になる。結果は「最適化で削除してしまう」に限らず、何でもアリだよ。
これが「「同一のメモリを違う型としてalias」に該当しないという理屈も無いでしょ。

memcpy の結果が定義されてるのは、同じ型のオブジェクト間でのコピーだけだったかと。
違う型の間で memcpy した結果の値が実は定義されてるということなら実に興味深いので
ぜひ規格の該当箇所を示して欲しい。

この場合の C スタイルキャストの動作は reinterpret_cast に丸投げされるだけなので話は変わらないよ。
2017/11/18(土) 23:37:48.32ID:5VdCNKN70
ここまでnextafter/nexttowardが出てきていない
2017/11/18(土) 23:38:32.35ID:euoYf0NO0
>>778
> "*(long long*)&f = i" は double 型のオブジェクトに long long 型の参照を通してアクセスしているので
してないぞ。
それは「fのアドレスを(long long*)にキャスト(この時点でlong long*型)したアドレスに対しiを書き込め」
であって、つまり long long に long long を書いている。だからmovが出る。
逆に f = *(double*)&i; は double に double を書くから fmov が出る。
その後の最適化で変更されるのはまた別の話。

> static_cast じゃコンパイル通らない。
だったら最初から>>759の言うとおり、reinterpret_castでいいだろ。

> 違う型の間で memcpy した結果の値が実は定義されてる
void* と void* なんだから同じ型だろ。何言ってんだ?

お前、基本的に理解がずれてね?
2017/11/18(土) 23:47:06.34ID:np1Yc2el0
>>780
なるほど、オブジェクトの型と式の型との区別がついてないんだね。
そこの理解無しで aliasing rule に関する話は無理だから、
C++ の規格を読み直すなりして区別が付くようになってからの出直しをおすすめする。
2017/11/18(土) 23:50:31.47ID:euoYf0NO0
>>781
俺には君が全く理解出来てないように見えるけどね。
まあ平行線だろうし、終わりでいいけど。
2017/11/19(日) 00:03:31.90ID:xhmNfS4m0
>>782
そうなると GCC も「全く理解出来てない」ことになるねぇ。
https://wandbox.org/permlink/WMFUTpXAgs2oZuos
> prog.cc:5:17: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
> *(long long*)&f = i;
> ^
> prog.cc:6:18: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
> f = *(double*)&i;
> ^
2017/11/19(日) 00:12:55.40ID:XAwzlQ9S0
>>782
それ以上恥かきたくなかったらこれ読んでくるといいよ
http://blog-ja.intransient.info/2011/05/c-13.html
2017/11/19(日) 00:41:57.82ID:p3uF8GIb0
まあ未定義な動作がどこまで行っても未定義な動作であって(教条主義的には)悪なのは確かだが
>>784のリンク先のを読むと
>ストアによってPの値が変わる可能性を考慮しなくてはいけないからだ。
という理由で最適化できないケースがあるから考慮する代りに未定義動作ということにしますた!
というだけで、ストアによってPの値が変わらないなら特に問題を生じないように思える…

で、ストアによってPの値が変わるケースというのは
int main() {
P = (float*)&P; // このキャストによって zero_array の中で TBAA 違反となる
zero_array();
}
みたいな変態的なケースしかなさげ;
2017/11/19(日) 00:54:18.30ID:SsMAbqSz0
>>784
答え書いてんじゃねーかよ。

> この種の未定義な振る舞いは、-fno-strict-aliasing フラグを指定することで無効にすることができ
つまり指定すれば万事解決だ。
ただその前にwarning出てても動作するとは思うが。

> この種の型の乱用はあまり一般的ではないので、標準委員会は、"妥当な" 型のキャストによる予期しない結果と引き換えに、大幅なパフォーマンス向上を選んだ。
これっていつから?LLVMに乗せた頃からっぽいが、、、日付や元URL見るかぎりC++11からか?
あとこれって、Cもか?
(Cでは俺が書いたようなキャストは常用されているから)
知っている人がいたらよろしく。
2017/11/19(日) 01:21:45.70ID:p3uF8GIb0
つかmemset(buf, ch, nのbufって__restrictじゃなかったのか…
今知った……
2017/11/19(日) 01:24:03.10ID:XAwzlQ9S0
C89からずーっとそうだよ
お前が書いてるコードが動いてるのは、コンパイラがそうしないという保証を独自に与えているか(-fno-strict-aliasingはその一例)
さもなくばたまたま動いてるだけ
2017/11/19(日) 01:33:36.82ID:xhmNfS4m0
>>786
広く知れ渡ったのは gcc 2.95 で実際にそのルールに基づく最適化が行われるようになってからかな。
https://www.gnu.org/software/gcc/gcc-2.95/features.html
> - Type based alias analysis is enabled by default. ...
そこから数えてももう 20 年近く経つわけだが。

知らずにそんなキャスト常用してるなら是非悔い改めてくれ。
2017/11/19(日) 01:35:13.22ID:p3uF8GIb0
(ま、__restrictな形でしかポインタしか使わない漏れには関係ないし…
2017/11/19(日) 01:37:52.26ID:XAwzlQ9S0
ちなみに-fno-strict-aliasing付けるとこんな基本的な最適化さえ出来なくなって
パフォーマンスが激悪化する可能性があるからな
それを完全に理解した上で万事解決だと言ってるならそれでもいいけどさ

int foo(double* pd){
 int k = 42;
 *pd = 666;
 return k * 2;
}

-fno-strict-aliasingを付けた場合、戻り値を"84"に最適化することは出来ない
なぜならpdのアドレスが&kを指してるかもしれないから
(strict aliasing ruleが効いてればdouble*がintを指してたら未定義動作なのでケアする必要がなく最適化できる)
2017/11/19(日) 01:42:54.83ID:xhmNfS4m0
>>791
引数で受け取った(有効な)ポインタが関数内のローカル変数を指すことは不可能だから、その例は最適化できるよ。
2017/11/19(日) 02:15:02.16ID:XAwzlQ9S0
有効なポインタならね
デタラメなポインタがたまたま&kを指してるかもしれない
普通はそんなのは未定義動作だからケアしないんだけどそれをケアしろって言うのが-fno-strict-aliasing
2017/11/19(日) 02:22:43.60ID:SsMAbqSz0
>>789
> mempcy なら動作が定義されてるかというとそうでもないんで (>>769)
これは間違いだろ。784内見る限り、
> Cは、このような型変換をmemcpyを使って実現することを要求している。
なら、memcpy使えば正しい結果が得られるはずだし、そうじゃないとコンパイラのバグになる。
つまり、>>763のコードは正しく動くはず、と読めるが。

ちなみに>>783のページで色々試してみた。(もし編集が残っているようならすまん)
全てgcc 7.2.0 で、結果は以下。
・CはC11/C11(GNU)の両方でwarinigも何もでない。
・C++はこの中の一番古いC++03/C++03(GNU)の両方でwarinigは出る。
ということはかなり昔からC++ではそうだった、ということだね。全く知らんかったわ。
ここら辺がCの連中がC++を嫌っているところなのかもしれない。

>>788
おお、サンクス、C++89からか。
俺環はVC++2008だからね。MS側が吸収してくれてるわけか。

>>789
いや俺環では問題ないしな。
つかたぶんこれC++の話で、上記試した限りCなら問題ないんだよ。
ただ俺はbetterCの人だから、まあ微妙なわけだが、、、VC++2017とかに移行するときは気をつけるよ。

さてそのリンク先
https://www.gnu.org/software/gcc/news/alias.html
も読んでみたが、つまり s->x_m[i] は s->a_m と型が違うから上書きしないはず、
だからループ内で毎回 s->a_m を取らずに前回の値をそのまま使っていい、ということらしい。(s->b_mも同様)
ただこれなら
for (unsigned long long i = 0; i <= -1; ++i) *(long long*)&f = i;
は確実に動くけどな。ここで端折られるのはfのアドレス確認 &f 部分だけだから。
ただしstackoverflowの連中は言っていることが少し違うから、もうちょっと確認が必要だが。
2017/11/19(日) 02:26:53.00ID:xhmNfS4m0
>>793
んなこたーない。
https://godbolt.org/g/wDD6Zk
2017/11/19(日) 02:37:45.46ID:SsMAbqSz0
>>791
周回遅れですまんが俺には794に書いたとおり、
・型違いは全てmemcpy使え。
と読める。だから763のコードはOKだと。

>>791-793の内容は理解した。
さて再度だが、やはり以下は動くだろ。

for (unsigned long long i = 0; i <= -1; ++i) *(long long*)&f = i;

ここで問題なのは、「fがiのアドレスをさしてたら未定義動作(&f==&i等)」であって、
i をコピーしてやらない、ではない。
791-793の言い分どおりなら、これはwarningが出てるだけで全く問題なく動くはず。
ただしstackoverflowの連中はちょっと違うことを言っているが。
2017/11/19(日) 02:42:26.05ID:xhmNfS4m0
>>794
C の aliasing rule には memcpy, memmove によって宣言型を持たない(たとえば
malloc で確保した)オブジェクトの型 (effective type) を変更できるという規定がある。
引用された「memcpyを使って実現することを要求している」はこのことだろう。

でも、 C++ にはこれに相当する規定が無い。
2017/11/19(日) 02:53:12.72ID:xhmNfS4m0
>>796
残念、まだ理解できてないよ。

答えは >778 にある。
> "*(long long*)&f = i" は double 型のオブジェクトに long long 型の参照を通してアクセスしているので
> 未定義動作になる。結果は「最適化で削除してしまう」に限らず、何でもアリだよ。

これ以上は規格見てからしゃべってくれ。
2017/11/19(日) 03:03:03.03ID:SsMAbqSz0
てゆーか、見てなかったけど763はfor文回らねーじゃねーかよ!

>>798
ちょうどよかったので今>>795を改造してアセンブラ見てるんだが、、、すまんが今日は寝る。
昼前にはまた書くよ。
2017/11/19(日) 06:07:15.51ID:p3uF8GIb0
未定義動作マジコエー;;(>>784のリンク先の次のページ
ttp://blog-ja.intransient.info/2011/05/c-23.html
2017/11/19(日) 06:25:20.22ID:p3uF8GIb0
プロセス屋さんががんばってCPUを3年ごとに倍早くしてくれるのだから
我々ソフト屋は口を開けて待っているだけにして
最適化なんてやめてしまえば良いのに

我々が忙しく働くということは、それだけバグを産むということなのだ…!
2017/11/19(日) 07:18:18.83ID:mXpVaiBzr
>>795
出来ると主張する人に対して
たまたまできない一例を根拠に
出来ないことの立証を主張されても…
803デフォルトの名無しさん (ワッチョイ 82a4-Eq1o)
垢版 |
2017/11/19(日) 07:18:20.90ID:Rb2sIcHm0
CPUだけ速くなってもDRAMの速度が昔のままだ
.7CRなんて法則を持ち出すまでもなく
現実にCPU速度が飽和したと感じたことなどないはずだが
2017/11/19(日) 07:23:52.01ID:mXpVaiBzr
>>795
>>802は夢をみた。忘れて
2017/11/19(日) 08:50:45.23ID:OzmZfN1I0
>>768
読んでも分からないときは?
806デフォルトの名無しさん (ワッチョイ 82a4-Eq1o)
垢版 |
2017/11/19(日) 10:12:41.15ID:Rb2sIcHm0
>>805
ここで実験してみるとか
https://people.rit.edu/meseec/eecc250-winter99/IEEE-754hex32.html
2017/11/19(日) 13:02:38.85ID:SsMAbqSz0
>>795改造は-fno-strict-aliasing有り無しによらず動くコードが出た。詳細は以下。

https://godbolt.org/g/QaSwTn
-O3 -fno-strict-aliasing -std=c++14 -pedantic -Wall -Wextra で mov QWORD PTR [rsp+8], rbx (27,29行目)が出る。
-fno-strict-aliasing を切っても同じ mov 命令が出る。
だからこれはwarningが出ているだけで動くコードが出る。
このときのコードは以下。
void test() {
double f = 0;
for (long long i = 0; i <= 10; ++i) {
*(long long*)&f = i; // (A)
std::cout << f << std::endl; // (B)
}
}
2017/11/19(日) 13:04:16.49ID:SsMAbqSz0
>>798
なお上記のGCC結果、或いは以下GCCのドキュメントは読んだ。
(ついでに後出の仕様書もチラ見したが、やはり今のところ君の理解がずれてるという見解だ。)
https://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Optimize-Options.html#index-fstrict_002daliasing-750
ここでは以下コードがアウトだと言っている。
union a_union {
int i;
double d;
};
int f() {
double d = 3.0; // (C)
return ((union a_union *) &d)->i; // (D)
}
アウトな理由だが、上記と794内URLによると、「『型違いのaliasはない』と仮定して最適化」する為であり、
つまり(C)はd名でdoubleに書き(D)はi名でint読み出しだから(C)と(D)は関係ない、
よって(C)はデッドコードでいきなり(D)の読み出ししてよし、ということらしい。

ただこれだとやはり上記(A)(B)は動く。(A)も(B)もfの読み書きであり、aliasして無いからだ。
この規定は「型違いの『aliasは』ないものとみなす」であり、aliasしてなければ関係ない。
今のところ見る限り、他の例も必ずalias(別名でアクセス)している。

なお正しくはunionを使え、ということらしい。>>763
まあ確かにunionはこれ用ではあるが、単発ならCキャストする奴が多いとは思う。
そもそもunionは撲滅対象だと思っていたのだが、これは意外だ。
(或いは仕様上 char*, unsigned char* については許可《どう見ても妥協だが》しているので、void*ではなくchar*にすればいい)
2017/11/19(日) 13:06:08.29ID:SsMAbqSz0
仕様書は以下でいいか?読み慣れてないからだいぶ推測が入るが、
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
俺の結論は以下かな。

・gccのは -fstrict-aliasing で、あくまで alias についてだが、仕様書内は alias なんて関係ない。
・fstrict-aliasing 出来る理由が3.10.10によるのなら、reinterpret_castの存在価値はなく、仕様書内に矛盾がある。
・おそらく reinterpret_cast 撲滅で union に書き換えろ、という方向か?
aliasってのは多分折衷案で、union 以外は全部アウトにしたいっぽい。

詳細は以下。

5.2.10 Reinterpret castでは特に妙なところはなし、型キャストは為される。
aliasについては3.10.10だが、reinterpret_castしてれば the dynamic type 扱いでアクセスに問題なし、と見る。
3.10.10.の注 54) The intent of this list is to specify those circumstances in which an object may or may not be aliased.
なんだから、やはりこれは alias されているかどうか?であって、アクセスできるかどうかではない。
ただしここを根拠に undefined behavior だから最適化してよし、としてるのはかなり強引で、
(というかここでalias云々がかなり唐突で、そもそもaliasの話をここではしていない)
(D)がreinterpret_cast扱いだというのなら仕様内に矛盾があることになる。
そしてこの解釈(=reinterpret_castされたものは the dynamic type ではなく undefied behaviorだからどうなってもよし)が通るのなら、
reinterpret_castの存在価値がなくなってしまうし、
aliasとかせこいことを言わず、reinterpret_cast相当のところは全部undefined扱いで削除していいことになる。
というか、多分コンパイラ側はこの主張で、これに対してユーザ側が反対し、
結果、 alias とかいう折衷案でごまかしているように読める。(既に書いたがaliasが唐突過ぎ)
確かに正しくはunionを使うべきであり、この流れだと将来的には reinterpret_cast は廃止で union しろってことになるのか?
しかし逆に言えば、C++89以来これで大して変わらないのなら、早々急に変わることもないか。
2017/11/19(日) 14:06:40.01ID:PnhOPMpK0
>>787
ポインタの引数が1つしかないのに__restrictつける意味ないからでしょ
2017/11/19(日) 14:19:11.46ID:p3uF8GIb0
コンパイラがうまくType-Based Alias Analysis出来るケースをいくら列挙したところで
Type-Based Alias Analysisできないケースが簡単に生じることは否定できない事実じゃんヤバイじゃん?

unionの使用が解決策というのも語弊があって、unionのメンバのアドレスを取ってから関数foo()に渡す手順だと
foo()のコンパイル時には渡ってきた2つのポインタが、型が違うけど(ループ変数などの条件次第で)同じ領域を指す(ことがある)
かどうか(ループを実際に実行してみねば)判断つかないじゃん?→コンパイラは怖くてループをmemcpy()やmemset()に置き換えられない

つまりunionこそ別の翻訳単位に属する関数に下手な渡り方をするとaliasingのすくつと化す気配が微レ存

元を断つにはやっぱID:xhmNfS4m0やGCC様がおっしゃるように、
そもそも型の混同要因(つまりポインタのキャスト)を絶つか、最適化が効いてほしい関数でプログラマが明示的に__restrictするしか、

※ 個人の感想です
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況