C++相談室 part135
■ このスレッドは過去ログ倉庫に格納されています
次スレを立てる時は本文の1行目に以下を追加して下さい。 !extend:on:vvvvv:1000:512 C++に関する質問やら話題やらはこちらへどうぞ。 ただし質問の前にはFAQに一通り目を通してください。 IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。 前スレ C++相談室 part134 http://mevius.5ch.net/test/read.cgi/tech/1516406742/ このスレもよろしくね。 【初心者歓迎】C/C++室 Ver.102【環境依存OK】 http://mevius.5ch.net/test/read.cgi/tech/1509780815/ ■長いソースを貼るときはここへ。■ 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 どの言語でも、入門書の次は、Effective 何々 >>625 「なぜ」そうするのか 「なぜ」そうなっているのか 他にどんな選択があったのか という思考回路の俺には合わない本だ >>623 それは低級言語に求める物じゃない C/C++は低級言語として数十年間圧倒的なシェアであり続けている これってすごいことだと思う >>623 データ構造の要素が静的に型が決まろうがそうでなかろうが、必要な要素数のメモリを確保する作業に違いはない。 せいぜい型のサイズを余計に掛け算するくらいだ。 確保するサイズが間違っていれば静的に型が決まろうがメモリ破壊は起きる。 もう少し具体的に示してくれないか? 静的な型の恩恵がどうたらって mallocがvoid*を返すのと同じだろ 問題ちゃ問題だがそんなもん怖がるやつぁC使いに向かない >>629 静的なら実行時パフォーマンスには影響しない >>630 「既に壊しうるのだからちょっとくらい壊せる場所増やしてもいいでしょ」には無条件では同意しかねる >>631 向いていようがいまいがCの案件はあるわけで, 可能な限り安全にコーディングしたいと思うのは可笑しいか? で話を戻すと, 汎用コンテナのCでの実装には, 大きく分けてもdefine使った型安全な実装とvoid *を使ったオーバーヘッドあり型安全なし実装が考えられるわけで, まずそれだけでこうして対立し得る 実装上でもいずれもpros/consがあるわけで, そりゃ規格がまとまる道理がないよね, って主張 別に必要最小限の機能で自分で実装することを否定するわけじゃないし, 型安全が絶対だという気もない 高速コンパクトと安全性利便性は相反するものだ 諦めろ >>627 独習の次に Effective C++/Effective Modern C++ は飛躍しすぎではないかな? ついてこれるのか >>632 > void *を使ったオーバーヘッドあり とは何?サイズ管理+アドレスの計算のこと? だったらC++の汎用コンテナでも同じ事を内部でやっているし、オーバーヘッドはないが。 見た目でしか分からない人はCに向いていないぞ。 というか、型安全が欲しければC++を、 そんなん要らんから小さくて早いコードを、というのならCを、ってだけだろ。 その分自分で管理する項目が増えるだけの話で。 選択肢はユーザー側に与えられているのだから、それ以上は要らんだろ。 >>632 できねえこと言ったってしゃーないだろ Cにはテンプレートがない 諦めるしかない とりあえずスクリプト言語やC#で書く→速くしたい所をC++で書く→もっと速くしたい所をCやasmで書く これが正解 どれかにこだわって対立させて排他するのはアホ >>638 同意。 若い奴が統一言語「○○だけ勉強すれば全ておk」を求めるのは自然だが、 そうなっていないのは理由があって、つまりは手抜きと実行効率(速度)の兼ね合いだ。 一時期Cが統一言語だったが、それは他言語がゴミだったから(対抗馬がLisp)であって、 C++で再統一されることはないよ。特に今のC++では。 オーバーヘッドについては撤回 >>636-639 だから基本的にそういう役割分担について否定しているわけじゃない Cで汎用コンテナが標準化されることはないだろうっていうのが元々の主張 >>638 Cで書けることは基本C++で書ける C++で最適化出来ない所はCでも無理 アセンブラしかない >>636 CやC++に関わらず専用なコードは汎用に比べて高速コンパクトに出来る事がある つまり、 void*で作って全てのコンテナサイズ(型)同一コードよりも型ごとにコードを作る方が速いことがある C++のコンテナは全て専用コードなので コードの肥大化と引き換えに微妙に速いかもしれない コードの肥大化によってキャッシュミスして遅い可能性もあるけど >>638 > 速くしたい所をC++で書く→もっと速くしたい所をCやasmで書く asmはいいとしてC++→Cでもっと速くなるケースなんてあるのか? >>632 >すでに壊してるのだから 一体どこからそんな主張を読み取ったんだ? 勝手に人の主張を捏造せずに、ちゃんと質問に答えてくれないか? あと、void*使わなくても、生成時に型サイズを受け取る方法もある。 汎用コンテナ作るのにdefineで型定義なんてするわけないだろう。 >>642 qsortやbsearchとかそうだよな C++のsortやbinary_searchには絶対に敵わない >>644 FF外から失礼します 「すでに壊してるのだから」とはどこにも書いてないと思うのですが なぜあなたこそ勝手に人の主張を捏造しているのでしょうか? FF外から失礼しました >>646 面倒なやつだな。 「既に壊しうるのだから」 これでいいか? 汎用バイナリ < 汎用コード専用バイナリ < 専用コード 速度的にはこう 速度が非常に重要であれば CだろうがC++だろうが専用コードを書くのが一番 >>643 間接参照を抜ける場合とかだろ。 逆にCよりもC++の方が速くなるコードの方があり得ないと思うが。 実際にC++はCより遅いってのは事実だし。 >>645 お前が値配列と参照配列の区別が付いてないだけだろ。 >>653 アンカーミスったか? qsortとstd::sortはどちらも値であろうが参照(ポインタ)であろうが使えるぞ >>653 > 間接参照を抜ける場合とかだろ。 それC++のまま書き換えればいいだけ > 逆にCよりもC++の方が速くなるコードの方があり得ないと思うが。 そんな主張はしてない > 実際にC++はCより遅いってのは事実だし。 だからどんなケースなんだよ STLとか使いまくって遅いとかなら使わないように書き換えればいいだけだろ 厳密に言うと C11の可変長配列はC++には無い C++では例外処理を実現するために関数コールに微妙なオーバーヘッドがある場合がある って感じでCの方が有利な事がある どちらもガシガシに最適化した場合の話 x86-32 例外処理を有効にすると 関数コールに微妙なオーバーヘッドが加わる x86-64 例外処理の為のオーバーヘッドは無い その代わり例外発生時の処理は非常に遅い Cの可変長配列のような、スタックに可変長サイズを確保する手段はC++には無い 当然ダイナミックなメモリアロケートよりはスタックに確保した方が速い ただし実際にはあまり使われていないと思われる >>654 ミスってないぞ。 >>656 Cの場合は抽象化してくれないんだから、関数を直接呼ぶしかないんだよ。 だから動的解決をしている場合はC++の方が遅く、静的解決の場合は同速になる。 CのほうがC++より遅いケース出してみろ。ないから。 C++は機能的にはCをラップしてるんだよ。 例外とか、クラスの動的解決とか、スマポ(キリッとか。その分管理が楽だが、速度は遅くなる。 Cの場合はC++のラッパ抜きで直接呼ぶことになるから、その分速い。それだけ。 >>658 > x86-64 > 例外処理の為のオーバーヘッドは無い > その代わり例外発生時の処理は非常に遅い これマジ? 煽りじゃなくて仕組みを知りたいから、キーワードかURLくれ。 こちらでググって確認する。 自分でディスアセンブルしたり バイナリ比較したり実測してわかったことで 仕組みがまとめて書いてあるような所は知らない >>656 > だからどんなケースなんだよ 探してやったぞ。 > 実験によれば 6-13% の実行時間が単なる関数のディスパッチに用いられ、オーバーヘッドは場合によって 50% に達する[1]。 > https://ja.wikipedia.org/wiki/%E4%BB%AE%E6%83%B3%E9%96%A2%E6%95%B0%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB C++は動的な型の変更はなしなので、コンパイル時に対象関数は確定するだろ。それが仮想関数であってもね。 だからvtblを用いた実装自体がコンパイラの単純さを採って、実行速度を捨ててる。 JavaScriptみたいに、実行時に型を変更してしまえる言語ではないのだから、 型毎にテーブルを持つこと自体が冗長で、 テンプレートみたいに、仮想関数が上書きされた毎時点で平面的に展開し、直接それを呼ぶ実装も出来るんだよ。 勿論オブジェクトコードは膨らむが。 Cの場合は、どちらでやるにしても「自前で」実装するしかない。だから当然、選べる。 C++の場合は、選べないでしょ。一般的にvtblの実装になる。(コンパイラの都合だが) C/C++で基本同じ結果となるコードが書ける 同じ結果となるコードを書けば結果は同じ ってだけで 当然違う結果となるコードを比べれば違う結果になる 当たり前 >>661 ちなみに計測したときのOSは何? なおその兆候が正しいなら、x64の場合はハードウェアで対応していることになる。 クラス関数はthisを第一パラメータとして渡してるだけで、これは構造体でも同じことが出来る virtual関数は関数ポインタテーブルへのポインタを持ってるだけ 同じことは当然Cの構造体でも出来る テンプレートは型ごとにコードを書くのと同じ >>663 だから、いわゆるC++の機能を使ったら、管理が楽になる分だけ遅くなる、というだけ。 C++の機能を全く使わないコードはCと言うんだよ。 だから、C++はCより常に遅い。それだけ。 >>664 そういえば、 例外発生時のスタックにあるリターンアドレスを検索するとかどこかでみたような どこかに仕組みが書いてあった気がしてきた >>665 > virtual関数は関数ポインタテーブルへのポインタを持ってるだけ > 同じことは当然Cの構造体でも出来る Cでやる場合は、関数ポインタを引数で渡すことも出来るんだよ。 (勿論C++でも出来るが、クラスを使う意味が無くなるから普通はやらない) この場合、間接参照が抜ける分だけ速くなる。 (実際はメモリアクセス1個よりはキャッシュを壊すことの影響の方が大きいとは思うが) C++独自の機能を使うとCより常に遅い? それは嘘だな >>669 C++にだけ独自の縛りを設けてCのが速い? 強引に主張を通したいのはわかるが そろそろ痛いぞおまえ >>667 それはスタックウォークという、従来の例外実装方法だ。 君の場合なら、x86がそれになってる。 >>670 ならC++の機能を使って、Cよりも速くなるケースを挙げてみろ。 ないから。 もとは>>638 だ C++で最適化に行き詰まった時に わざわざコンパイラをCに変えて最適化する事なんてないから Cっぽい記述とかアセンブラっぽい記述とかなら そりゃいくらでも >>672 前半 自分で調べろ >>672 後半 ええと、... 「C++独自の機能を使うとCより常に遅い」 の否定はわかるかな? >>658 って単に32bitプログラムを64bit CPUで走らせてオーバーヘッドがーって言ってるんじゃね? >>674 君は理解できてないようだから、定義を確認しておこう。 ただしこれは一般的な解釈であり、おそらくこのスレの住民は共有してる。 ・テンプレート、クラス構文、スマポ等、 C++コンパイラではないと通らない機能を使ったコードを、C++のコードという。 ・その他、関数ポインタ等、Cコンパイラでも通る機能のみで書かれたコードを、Cのコードという。 > 一般に、カーネルモジュールをC++で設計するやつは、以下のいずれかだ。 > > (a) 好んで厄介事に巻き込まれたい者 > (b) 自分が書いているのは実はCだと気がついていないC++バカ > (c) 授業でそういう課題を与えられた者 > > (d)を付け加えるなら好きにしてくれ。 > > Linus > https://cpplover.blogspot.jp/2013/05/linus-torvalsc.html 君は多分(b)だね。 今の話題はC++のコードとCのコードの速度比較ということでよろしく。 >>673 > C++で最適化に行き詰まった時に > わざわざコンパイラをCに変えて最適化する事なんてないから そんな話は誰もしてない。 勿論その場合はCのコードに変更し、C++コンパイラを使うに決まっている。 じゃないと他の部分が通らないだろ。 君の定義は、C++コンパイラを使っていればどういう書き方であってC++ということだったのか。 なら話は噛み合わないさ。 #define SIZE 100000000 long long array[SIZE]; int comp(void const* lhs, void const* rhs) { if(*(long long*)lhs < *(long long*)rhs) return -1; if(*(long long*)lhs > *(long long*)rhs) return +1; return 0; } int main(void) { clock_t t0 = clock(); qsort(array, SIZE, sizeof(long long), comp); clock_t t1 = clock(); printf("%g[sec]\n", (double)(t1 - t0) / CLOCKS_PER_SEC); //2.288[sec] } #define SIZE 100000000 long long array[SIZE]; int main(void) { clock_t t0 = clock(); std::sort(array, array + SIZE, std::less<long long>()); clock_t t1 = clock(); printf("%g[sec]\n", (double)(t1 - t0) / CLOCKS_PER_SEC); //8.245[sec] ・・・あれ? 何だこりゃ } >>657-658 そういやスタックにとる可変長配列はC++にないんだな まあメジャーな環境でalloca( )使えないものはないと思うが 例外は使わないようにすればいいだけかと >>678 一応、基本的確認をするが…データは同じなんだよな? 俺の予測では同速。多分そちらの期待も同じだと思うが。 >>676 > ・その他、関数ポインタ等、Cコンパイラでも通る機能のみで書かれたコードを、Cのコードという。 可変長配列とか使ってないならC++のコードでもある つまりC++の範疇で書き直してるだけ って言うのが大方の人の解釈だと思うが >>676 それは単なる君の定義 100歩譲っても5chで一般的なだけ 普通C言語, C++と言えば、 その規格や規格に準拠したコードを表す >>681 それは君の勘違いだね。 その定義ならC/C++を区別する理由がないし、多分LinuxもC++になってしまうだろ。 >>676 たとえばヘッダファイルなんか、同一のファイルを Cコンパイラに入力したり C++コンパイラに入力したり ってこともあるよな 内容には無関係で単に Cコンパイラに入力したらCのコードで C++コンパイラに入力したらC++のコードだろ 最適化の内容だってrestrictのように CとC++で違ってくる可能性はあるしな >>682 最適化の掛け忘れでは? Cの方はほぼ最適コードだが、(メモリアクセス減らして一時変数に取れとかその程度) C++の方は最適化無しだとトンデモコードが出てくるが、 最適化でそれを消すからおkというノリだったと思ったぞ。 最適化無し同士の比較は意味がない。最大最適化同士の比較やってみそ。 使うモジュールの差を言語で言うから話が紛れる で、 君の定義であるごく一般的な記述を行った場合の話であれば C++の方が速いこともあるしCの方が速いこともある C++はテンプレートによって専用のコードをたくさん作る 当然汎用バイナリよりも専用バイナリの方が最適化がかかりやすいし、 変数よりも即値の方が速いことも多い C++例外処理も有効で、 これによって処理が速くなる場合がある >>686 gcc unko.c -O3でやってる >>685 > 内容には無関係で単に Linus全否定かよ。 >>682 オールゼロでクイックソート? それは... >>687 > 君の定義であるごく一般的な記述を行った場合の話であれば > C++の方が速いこともあるしCの方が速いこともある ねーよ。 実例挙げてみ? それって単なるコンパイラの適性であって、コード自体の速度ではないだろ。 C++とCの本質的な速度差ってのは絶対にひっくり返らないものであって、 例えば、スマポを使っている限り参照ポインタを管理する分だけ遅くなる、というもの。 コンパイラがどう進化しても、「0」「ADDまたはDEC命令」の差はひっくり返らないんだよ。 > C++例外処理も有効で、 > これによって処理が速くなる場合がある ねーよ。Cは最初から全部noexceptだ。 ソートって メモリサイズ 比較コスト コピーコスト キャッシュサイズ ... こんなんで結果(時間)が大きく異なるんだよね クイックソートだと データの並び順でもたまたま選んだピボット値でも変わる 1個の場合を比較してもあまり意味が無いぞ clでやってみたら期待どおりの結果になった >>677 1.789[sec] >>678 0.623[sec] 最適化は/Ox >>690 ああ、それは確かに テストデータをまじめに作るか。。。 >>688 となるとアセンブラを確認するしかないね。 (いいサイトはあったはずだが、普段使わんから忘れた) >>693 それさ、以下の3条件でやってみ。 1) Cのコード(677)を、Cコンパイラ 2) Cのコード(677)を、C++コンパイラ ←追加 3) C++のコー(678)を、C++コンパイラ Cコンパイラってポインタ周りは最適化をかけないから、多分、 速度差はコンパイラ起因であって、コード起因では無いと思う。 >>696 > (b) 自分が書いているのは実はCだと気がついていないC++バカ > https://cpplover.blogspot.jp/2013/05/linus-torvalsc.html 君の定義が正しければ、上記(b)の定義が出来なくなるだろ。 >>691 C++が遅くなる例だけあげてC++が遅いって言ってもねえ C++が速い例 double p = 1.; int n; for (n = 1 ; ; n++){ p *= n; } C++だと例外処理をつかって、いつオーバーフローするかわかるんだけど 例外を使わないとどういうコードになるかねえ? --- Cで普通に汎用vectorを作るとすると 普通は汎用バイナリで作ることになるんで 関数ポインタを経由する事になっちゃうけど C++のテンプレートだとだとそれぞれ専用なんで 関数コールが速いよね アドレス計算も即値の乗算だから色々なテクニックが使える >>699 > C++が速い例 Java出身か?死ね C++だとコンテナを使ってまともなソートを簡単に書けるけど Cだと面倒だからバカソート ってのも普通にある 要素数が少なければ意図的にやったりもする 一般的なコードではCの方が速い事の方が多い ってくらいの主張にしとけば良いものを 強い主張をしちゃうから >>701 ん? 良くわからんが負け宣言てことでいいのかな? >>684 何を言ってるのか意味不明すぎる よほど感覚が独自なんだろうな w >>699 おっとすまん、ポインタアクセスでのメモリオーバーフローと勘違いしてた。 doubleの無限大の例外って事? 俺はそっちには詳しくないが、浮動小数点例外をソフトウェアで検出するのなら同じだし、 ハードウェアでの検出なら割り込みがかかるだけで、速度的にはこれまた同じだが。 vectorについては完全に君の勘違いだぞ。 Cではそれぞれ専用の物を作るのが基本であり、それを一つにかけるようにしたのがテンプレートだ。 多分、理解の仕方が逆だ。 >>699 > Cで普通に汎用vectorを作るとすると > 普通は汎用バイナリで作ることになるんで 速度云々議論してるところでそんなことする奴はバカって言われてもしょうがないと思う >>705 > ハードウェアでの検出なら割り込みがかかるだけで、速度的にはこれまた同じだが。 Cだと言語の範疇ではその割り込みを処理できない なのでif文とかでオーバーフローするのを検出するとかが必要 って話だろ >>707 > if文とかでオーバーフローするのを検出するとかが必要 ほう。ならそのコードを書いてみ。 そしたらそのコードの中でオーバーフローするから無限ループだね。 そんな言語が実用だったとでも? >>705 例外については「お前は頭が悪すぎて会話にならん」とだけ コンテナは 「C++の方が遅い例だけ扱って、速い例は自分の想定と違う」 という主張を続けるならお前と会話しても無意味だ IDが変わってしまった まあそんな事はどうでもいいか ちなみに速度比較についてはいろんな人が様々やってるけど、 俺的にまあ公平だと思えるのはこれだね。俺の体感ともだいたい一致する。 おれはC++は1.1-1.3位かと思っているけど。 > C 1.00 > C++ 1.56 > Java 1.89 > C# 3.14 > https://jaxenter.com/wp-content/uploads/2017/09/energy-efficient-languages-768x689.png > https://jaxenter.com/energy-efficient-programming-languages-137264.html C++の機能をバリバリに使ったら、そりゃJavaと大して変わらんだろ、ということになるし。 スマポってのは良くできたGCとコストはほぼ同じだし。(GCは全自動なだけ) Javaは以前は3程度だったが、ゴリゴリチューニングしてきているらしい。 >>706 速度優先のコード前提ってことなら 保護されまくった高機能汎用コンテナを使うこと自体アホってことになるねえ さらに条件を加えちゃってもう >>708 なんで喧嘩腰なのかがよくわからないけど、 C言語では「n <= DBL_MAX」というif文が必要ってことだろ? double p = 1.; int n; for (n = 1 ; n < DBL_MAX; n++){ p *= n; } >>714 いやオーバーフローするのは p だろ。 と思ったが、もしかして n の方なのか? >>716 通じたようで何より。 だからオーバーフローの検出はソフトウェアでは辛くて、通常はハードウェアのはずだ。 そしてその場合は割り込みとなり、Cの場合は割り込みハンドラにコードを書くことになる。 C++の場合は『そこから例外処理ルーチンまで引っ張ってきてくれるコード』をコンパイラが用意し、 ユーザーのcatchコードを実行する。つまり、上記『』内コードでラップされてる分だけ遅い。 (実際にはラップだけではなくスタックウォークも行うから相当遅いはずだが) なんだが、実際俺はゼロ割例外しか見てないからオーバーフローについてはよくは知らん。 ハードウェア的には上記の動作になる。 一般的にはオーバーフロー例外は出ない環境(無限大に貼り付けるだけ)で使うのではないかと。 Cではアホみたいにゼロ割チェックやってるよ。 これはC++でも同じだと思うが、C++erはやらないのが作法なのか? とはいえ、ゼロ割はCMP+Brachであり、通常は分岐しないから、x86ではほぼゼロコストだ。 割り込みは関数呼び出し自体が遅くなるから、結局これもCの方が速いはずだが。 >>712 お前話の流れが読めてないだろ w >>638 から読み直せ、バカ overflowてexception吐くんだっけか >>708 バカはこれだから w isfinite( ) マクロとかも知らんのかよ >>717 オーバーフローで例外や割り込みが起動することはないのでは? 普通、無符号ならキャリー、符号有りならオーバーフローのどっちかのフラグで判定するかと unsigned long long array[100000000]; ↑ ここに同じファイルから乱数を読み込んで比較してみた clのオプションは /Ox /arch:AVX gccのオプションは -O3 -mtune=sandybridge qsort cl 27.171[sec] gcc 26.139[sec] std::sort 途中で書き込まれてしまった unsigned long long array[100000000]; ↑ ここに同じファイルから乱数を読み込んで比較してみた clのオプションは /Ox /arch:AVX gccのオプションは -O3 -mtune=sandybridge qsort cl 27.171[sec] gcc 26.139[sec] std::sort cl 13.456[sec] gcc 9.103[sec] おまけ std::sortにstd::execution::parを指定してみた cl 3.288[sec] gcc 未実装 >>698 そこの2通目に箇条書きしてある部分は 1992年当時に俺が思っていたことに近い ・例外がクソ うん、マジクソだ C++11以後マシになったが下痢が治ったという程度 ・newいらねー 演算子newを初めて聞いた瞬間、 mallocの設計理念が大声でわめき立てた C++11以後ブーイングが更にエスカレートした ・キーワードclassいらねー 禿自身が認めやがった ・・・しかし、それがなぜ>>685 への反駁に引用されるのかがわからん ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる