VIDEO
C++ はそれなりに歴史が長いから仕様も変わってるし思想や習慣の変化もある。 上述で私は「inline は ODR の例外の意味!」と主張したけどさ、 D&E を読むと (inline 指定導入初期の判断としては) 「コンパイラによるインライン化の判断がザコなので指定できるようにした」 という意味のことを書いてあって、大元はやっぱりインライン化の指定なんだよね……。 色んな事情が絡むし、単純に C++ が巨大なのでどうせ一冊でちゃんとした理解にはならないと思う。 適当なやつをどれから読み始めてもいいんじゃないかね。 まあ、あまり古い奴は避けた方がよいだろうというのが最低限の基準かな。
C 言語でなぜかC++のコメント行がいつの間にか許されている不思議
>>24 ふむふむ。なかなか一筋縄ではいかない大人の事情ってのがてんこ盛り、ってことですね
私もそろそろ C++ をやり直そうかな‥‥
このコードがコンパイルできないんだけど、なんで? struct hoge { std::map<int, std::unique_ptr<struct hoge>> m = {}; void x() { struct hoge &r = *this; r = *(m.begin()->second.get()); // ここがまずい } };
コピーコンストラクタが呼ばれて、最終的にmapのunique_ptrがコピーできないってことか。。。 C++98の人間だし10年以上離れてたから最近のC++まったくわからんわ・・・
rは*thisの別名。 *thisの所有物を*thisにコピー。だめ。 *thisよりも高位じゃないと。。。
>>(前スレ)695
のFFTで2^(2^34)-1を計算する奴
https://ideone.com/xSaa6x を倍速で動くようにしたったわ……!
↓↓↓
https://ideone.com/q0O74K オリジナルが2200秒なところを962秒で計算完了
出力結果は一致
メモリ消費量はオリジナルと同等(完全in-place、sinテーブルは1GB(計算時間と誤差が劣化するがシュリンク可能))
さすがに天才の漏れも三角関数って何だっけというあたりからスタートしたので
日数がかかってしまったが、いまやバッタフライ演算を完全に理解したから
純アルゴリズム的には最善の実装になっていると言える(希ガス、
(参考)
基礎からの周波数分析(9)-「高速フーリエ変換(FFT)」
https://www.onosokki.co.jp/HP-WK/eMM_back/emm140.pdf あとはメモリアクセスの時間局所性を改善して1000倍にする、
こういうのに燃えてるような人が日本を支えていたのかもな
>>37 アホか
数論変換も知らんゴミが夏休みの自由研究やってるだけ
>>36 漏れや希ガスというタイポや、バタフライ演算とかいう大学2年の信号処理の課題で出る程度のアルゴリズムを自信満々に書いちゃうあたり、かわいそうな人なのかな
その辺はタイポじゃなくて20年近く前の2ch語なのじゃ…… イタいことには変わりないが
template <class T> void F(const T &t){ auto x = t; } って関数があった場合、autoで推論(導出?)されるxの方はconst T&になるの? ついでにここらへん分かりやすい資料があったら教えてほしい。
>>47 テンプレートの実引数推論と同じ規則が適用される。
つまり
template<class U> void foo(U u);
というテンプレートが仮にあったとして、これに
foo(t);
としたときの U の型がその場合の x の型になる。
故に x の型は T であって const も参照もつかない。
auto&にすればconst参照も推論されるし、右辺値も取り得るならauto&&にしておけば間違い無いんだっけ
auto& x = t;
と書いた場合には上述 (
>>48 ) の規則に当てはめると
template<class U> void foo(U& u);
と同等の推論をするし、
auto&& x = t;
と書いた場合には
template<class U> void foo(U&& u);
と同じ推論になるわけだね。
じゃぁ、あらゆる場面でauto&&と書くのはあり?
>>37-46 んまー藻前らの言う通り
>>(前スレ)695 のオリジナルのプログラムが書き方が変にIQ高すぎたせいで
漏れが普通に書いたプログラムの方が速かったということかもしれませ
んね、
しかしこれをここから2^3倍にするというのが真の天才の仕事なので
ご気体くだち、
なお^がべきなのか排他的論理和なのかは結果を見て決める、
operator^をべきにするやついたら当然シバくよな
addメンバ関数の引数(x)の所有権を、クラスの中の配列(vec)に移動させたい場合、std::moveをどこで使えばいいかわかりません。 struct A{ vector<vector<int>> vec; void add(vector<int> &&x){ ここで、std::moveを使ってpush_backに渡すべきか、渡さなくてもよいのか、わかりません。 1) vec.push_back(std::move(x)); 2) vec.push_back(x); どっちが正なのか?・・・ }; 〜〜〜〜 vector<int> x; A a; a.add(std::move(x));
>>59 move 使わないと移動しないでしょ。アドレス見るなりして確認できるはず。
>>60 「移動させたい」と言ってるんだから move で正しいでしょ。
>>59 C++ の常識的な設計としてはには
>>60 が主張するように forward を使うべき。
右辺値か左辺値かによって適切に切り替えが成されるので。
「常に」ムーブさせたいのであれば
>>61 の述べる通りだが、
その場合は a.add(std::move(x)); の move は不要。 (有っても害はないが……。)
左辺値でも add がムーブするなら右辺値にキャストする意味はない。
push_backが適切にやってくれるだろうし素人がここで手入れするところではないな
>>63 a.add(std::move(x)) の move 外したらコンパイルエラーになるでしょ。
そりゃド素人が作成した自作関数に&&しか定義してないからでしょ
>>65 ああそうか、すまん。
変な思い違いをしていた。
xをコンストラクタに渡すならemplaceじゃね?
これでいいってことですか? void add(vector<int> &&x){ vec.push_back(std::forward(x)); }; あと、 >「常に」ムーブさせたい という言葉が気になるんですが、右辺値を受け取る場合に「ムーブさせない」場合があるんでしょうか?
引数が forwarding reference になるのは型変数の場合だけ
https://en.cppreference.com/w/cpp/language/reference#Forwarding_references コンクリートな型の場合 && で取ったら確実に rvalue だから forward は要らん
んで vector<T>#push_back は (const T&) と (T&&) に対してオーバーロードされてるから (後者のバージョンが選ばれるので) move も要らん
つまり
>>64 が正解。なんで適当答える前に手元で確認しないのか
>>69 ムーブさせない場合はある。
それとは別に可能なら左辺値にも右辺値にも対応するのが通例なので
それを無意識に前提に入れてしまっておかしなことを書いてしまった。
ごめんね。
>>70 move しなかったら push_back(const T&) になっちゃうでしょ。なんで適当答える前に(ry
>>72 アホか。forwarding reference じゃなくて rvalue reference だっつってんのになる訳ねーだろ
あ、もしかして
>>59 の
> a.add(std::move(x));
について言ってんのか?そりゃここには move が要るが今は add の中の話だろ?
>>73 さてはrvalueの挙動理解してないな?
https://wandbox.org/permlink/rtkW4N7gWRu9yyqK rvalueとして受け取った時点でlvalue扱いなんだよ
moveするまで所有権を持っていて、moveで所有権を放棄する。
所有権はT&&を受け取る関数に移る。
>>69 moveさせるとまずいケースがある
https://wandbox.org/permlink/bdXnNaYzb7esxcwt moveってのは所有権の移動なので、所有権を他に渡した後に使うとまずい
このコードは手元のgccだとこんな感じに壊れる
forwardは2つのモードがあって、forward<T&>かforward<T&&> (or forward<T>) を指定しなきゃいけない。
T& forward<T&>: moveしない
T&& forward<T&&> (or forward<T>): moveする
Revive! Vive! unifyde call syntax!! revive!!!
cpp経験のあるエンジニアが面接に来たんですがboost知らないとかあり得るんでしょうか
でもC++を完全に理解してるスーパーエンジニアが君の会社に来ることはないんだ
boost知ってても使ってないとか黙殺するとかなら有り得るんじゃね
CとCppは似てるらしいけど最初はCから始めて 基礎を身につけた方がいいとかありますか?
まあコンパイル時間が伸びるとかで使わない所も多いしな
C++のほうがコンパイル時の文法チェックが親切なので、g++でコンパイルするのが吉
余談だけど cpp って書いたら C プリプロセッサのことを指す場合もある。
>>83-85 ありがとうございます!勉強になります!
今どきの人がCの機能を学ぶにしても、最初のうちはC++コンパイラを使ったほうがいい C++コンパイラは初心者がやりがちな意図しない型キャストに警告を出してくれる
>>79 やっぱ有り得ないですよね
うちの会社はC++使わないんですが、盛り過ぎた経歴は看過できないので二次面接にはC++経験のあるエンジニアに同席してもらいます
>>91 ずっと同じ部署にいてboostライブラリに接する機会がなかっただけじゃないかな
ずっと同じ部署にいたってことは専門性が高くて信頼されてた可能性がある
>>92 はい、私がC++は門外漢すぎて突っ込んだ質問が出来なかった手落ちもあるので、後続の面接ではしっかり見極めたいと思います
C++以外の話でも怪しい部分はありましたし
>>83 も書いてるけどboost使わない職場はそれなりにあるから俺もboost使える?って聞かれたら使ったことないからよく知らんって答えると思う
そもそもそんな事で採用決めるような会社はこちらから断ると思うが
はい、職歴に書かれた内容に曇りがないか見極めたかっだけなので、Boostに知見があるかどうかはさほど問題にしてません
>>78 バカか
boostは標準化されてないだろ
ヘッダ入れ込んでまでわざわざ使うヤツは縛りプレイヤーかマニアだぞ
>>79 はネタで言ってるかエアプだと思うよ
boost役に立つものもあるし個人では使うが、仕事で必須かというとそんなことはない
知ってるけどあんまり使ってない、使ったことないから詳しくは知らない、とかならまあ別に普通だけど 知らない聞いたことすらないってのはヤバい
仕事では使わないなあboost 必須のミドルウェアは使うけど
>>98 その標準じゃないもん、にはOSのAPIとか目的のソフトに必須のライブラリ群も含んでる?
boostもサードパーティのライブラリも使わんて人は、コマンドラインのパーサーとか任意精度のライブラリとか自分で毎回書いてるのか? 正気か?
そんな便利なものは存在しないから標準ライブラリ+Win32でどうにかしてるだけじゃね?
boost::sort::block_indirect_sort()はstd::sort()より速いので使ってる
>>102 コマンドラインのパーサー含め、その辺の文字列処理は全部自前の文字列クラスでやっちまうな、俺はw
いちいち文字コードがどうたらとか悩みたくないし
>>95 c++標準の勉強をしていれば単語としてboostを聞いたことあるだろう。
知らないのなら大した勉強はしていないだろうから、せいぜい業務で通り一辺触ったことがあるくらいじゃないかね。
どこまでのスキル求めているかによるけど、業務内容に近い課題を与えてテストしてみたらいいんじゃない?
業務でc++を使わないなら、c++スキルに金を払うわけじゃないから気にすんな。どうせ募集要項にc++とか書いてないんだろ。
自分の知ってる世界がすべてだと思ってる人間の方が危険。 C++が使われる範囲が広すぎるから、言語の経験有無よりもどの分野で開発してたのかを聞くべき。 ガラケー時代のカーネルドライバ書いてたり、携帯キャリア向け機器の組み込みやってた時はboostどころかstlすら使ってなかった。 というか使えなかった。 一方でスマホゲーのバックエンドを書いてた時はboostまみれだった。
boost知らない人は自分が使ってる環境がC++11/14/17/20なのかも知らないとかありそう 大昔のC++文法しか知らない人とかいるし 面接ではこれも聞いてほしい
昔はboostでも使わんと正規表現扱えなかったでしょ(ヽ´ω`) 今の子は知らんのかな?
今や正規表現ライブラリはpcre2使っておくのが最適解でしょ boostもre2も速度遅すぎ 最速軽量がre2の長所だったのは昔の話
Boost 内のライブラリは組み合わせやすかったりもするだろうし、単独で性能が良いというだけが指標ではないだろう。 もちろん性能が良いに越したことは無いが、数倍程度の違いなら全体としては問題にならないことも多い。
STLでregexクラステンプレートが追加されたのだから各正規表現ライブラリの供給元がstd::regexに準拠したラッパークラスを提供してくれるのかと思いきや、ほったらかしだしなあ
おまいの募集要項にboost使用するって描いてないならおまいが可笑しい boost以外の部分でC++の知識や使えるかどうかを確認するべき
ただの文字列なら速さで選ぶのも良いけど、HTMLやXMLのような注釈を含むテキストは、STLやboostを使うのがスマート。
re2は遅いうえに\1みたいな後方参照をサポートしてないのが痛い
別に即戦力求めてるわけじゃないので開発言語で縛って間口狭くしたくないんですよ でも質疑応答のクオリティ上げるためには突っ込んだ質問って必要じゃないですか 今回はそれが上手く出来なかっただけです
ようするに基礎があるかどうかと伸びしろがあるかどうかだろ 今知らなくても調べればすぐ判ることが出来れば問題無い罠
本人が経歴盛ってるならクズだが、営業やエージェントが勝手に盛ってることもあるからな その辺も見極めて大目に見てほしい
自分のとこが金をいくら出せるのか考えてからマウント取ってほしいもんだわ
対価は市場感より高めに設定していますね AWSと同じぐらいのはずです
>>117 そもそもそんな用途にC++ってどうなの?
htmlは知らんがxmlの読み書きはC++のプログラムで一般的じゃね
C言語の基本を学んでC++を勉強を始めました バッファのフラッシュについて教えてください プログラムは最後に全てのバッファがフラッシュされると思いますが、 std::flashやstd::endlはどういった時に使えばいいのでしょうか? また、フラッシュの処理時間を考えるとstd::endlよりも'\n'を使った方が軽くなると思いますが、 あえてstd::endlを使う意味はありますか? このフラッシュという概念はC言語になかったですよね…?
fflush()を知らずにC言語を使ってきたなら気にする必要はない
>>128 キミの疑問の中に答えがあると思うんだが
>プログラムは最後に全てのバッファがフラッシュされると思いますが、
逆に言えばプログラムの途中ではいつバッファの内容がflashされるかわからないってことじゃん
どういった時に使えばいいのか、なんてプログラムの最後ではなく途中でflashしたい時だろ
stderr(バッファリング無し)とstdout(デフォルトでバッファリング有り)のリダイレクト先が同じ(コンソール等)のとき、 printf()とfprintf()の実行順にprintf()とfprintf()の出力結果を並ばせたいときに早速ffush(stdout)の出番が、 あとfflush()せずにabort()したらバッファ上のデータが失われることがある もっともabort()を呼ぶしかない状況とかはどうしようもない状況なので盲目的なfflush()が適切とは言えないケースも ありえるかもし れんが
んまー通常はファイルのクローズでフラッシュされるから明示的にファイルポインタに対してfflush()する必要に迫られることはなさげ 腸人工的なシチュエーション(でありかあまり良い設計でない例)として、 オープンしたままのファイルA、Bにこの順でデータが追記されることを気体するプロセスが他に居るときに A、Bの順で追記するとき要る?ぐらい??
他のプロセスと通信する時に明示的なバッファフラッシュが必要になることがあるよ
>>133 それは思わないでもなかったが、
1. バッファに入った順で出ていく
2. ほっといてもバッファ内容がどんどん出ていく
3. 通信は送りっぱなしまたはロジカルなハンドシェーク手順
である場合にfflush()が必須というケースが思いつきませなんだ、
1行ごとに結構重い処理をしたり、std::cinが入ってくるタイミングが不定期だったりするときに1行ごとにflushしておくと便利。 C言語でも使うテクニックだけどね
送信側(自アプリ)じゃなくて受信側(他アプリ)の都合次第なので
>受信側(他アプリ)の都合次第 どのような都合かkwsk、 fflush()したら動いて、fflush()しないと止まってしまう通信処理とかはなんかおかしいのでは…… ほっといてもバッファ内容がどんどん出ていく 限りfflush()せずとも送信は成立する 受け取れたかどうかはACKかNAKでも返してもらえばワカルから、 受信タイムうアウト検知ぐらいしかタイミングが関係する要素は無さげ、
「受け取れたかどうかはACKかNAKでも返してもらえばワカル」ってのがすでに受信側の都合だろ
コンテキストスイッチをきっかけにフラッシュするような仕組みはあるん?
それがフラッシュしておかないと停電のときデータ全部持ってかれるんだよな
とりあえず言っておくが、水がもったいないからと言って水洗トイレを流さずに退出するのはやめたほうがいい
>>139 小便用トイレだと赤外線で退出を探知して水を流してくれるものもある
フラッシュってのはハードディスクにどこまでデータ書いたか正規化する目的で行うから、フラッシュしないで停電モードでクラッシュすると、復旧したときに書いてたデータはゼロバイトのままだったりするが、こまめにフラッシュでデータを確定申告してる場合は書いた分がきちんと残ってたりする
これからは税務署に追徴課税されないように足繁く通うことにします。
ま、無停電装置つけてたり電源不足などでHDDが頻繁に切断される環境でなければ問題ないけどね
一休はすでに縄を持って待ち構えてくれているのだから、義満が虎を屏風から追い出せばいいだけ 簡単なことだろ
誤解している人が多そうだけど fflush()はC標準ライブラリの中のバッファリングデータを全て吐き出すだけであって システムコールでいえばwriteするだけだよ 一方でカーネルがディスクなどに書き出すのを保証するのはシステムコールではsync/fsyncであってこれはfflush()しても行われない別のもの
遅レスすいません。 右辺値参照周りを自分でも見直してきたんですが、 最終的に「vecの要素」に所有権を押し付けるコードは↓で正しいのでしょうか? void add(vector<int> &&x){ vec.push_back(std::move(x)); }; ・std::forwardを使う場合は、型がテンプレートの場合(フォワーディング参照の場合)に使うのが一般的であって、 上では具体的な型(vector<int>)を指定しているので、forwardを使う場合に当てはまらない。 ・vector<int> &&xとして引数を受け取っても(右辺値参照として引数を受け取っても)、 右辺値参照自体は左辺値になるので、 vec.push_back(x)としてしまうと、呼ばれるpush_backは push_back(const T&)であり、所有権が移譲されない。 なので、ここでもmoveする必要がある(vec.push_back(std::move(x)) この理解であってますか?
>>147 sync sync sync
最後に電源切る前に
^C 連打ですね
判ります
WinだとFileFlushBuffersだけで完結する
noexceptの有無で動作が変わるなんてC++ムズすぎィ!
まあ原因と結果が全然離れた別の場所で起こるっていう意味では難易度高いとは思う
>>126 この国は累進課税なのでそのラインは難しいですね
>>66 の話は
>>59 へのだったのか?w
>>155 ほか回答頂いた方
ありがとうございました。
moveをやれるヤツはmoveをやる勇気があるヤツだけだ
>>138 話をそらすでないは;;;
通常のキャラクタ型デバイスならfflush()せずともバッファ内容がどんどん出ていって
受信側(他アプリ)に伝わるやんけ
fflush()全然必須じゃないやんけ
fflush()に関してはやっぱ受信側の都合も糞も無いやんけ;;;
んまー今日日の計算機は速いから、世迷言てんこ盛りの呪術指向プログラミングでも
比較的まともっぽく動くが、
fflush()にはフロー制御で止まっている送信を動かす力は無いし、
ブロック型デバイスの書き込みのトリガーになる保証は無いしで
やっぱ使いどころは
>>131 みたいに多対1の書き込み(dstが同じ)というケースでの論理的な書き込み順序保証ぐらいしか無さげ
受信側の都合どうこうの話は知らんが >通常のキャラクタ型デバイスならfflush()せずともバッファ内容がどんどん出ていって それは送信側がどんどん送り出している場合でしょ
高機能トイレしか使ったことない人は、何もしなくても離席したら勝手に排泄物が流されていくと思っているからね
むしろコンピュータ用語のflushの方がトイレからの連想
長時間ストリーミング書き込み時にFileFlushBuffersコールしてなかった停電時の悲劇
なんとなく分かりましたが、C言語でfflush()を使っていなかったので困ることもなさそうです 改行は'\n'を使ってもう少し勉強を進めてから改めて皆さんのレスを読み返そうと思います 返事が遅くなりました、ありがとうございました
>>163 ソフトウェアー呪術者、、、、
>>163 のような台詞はファイルをクローズしない人に言ったらよい
fflush()しないことにに当てはまらない理由はすでに述べているっつーの;;;
>>168 左様停電に対して備えたいならI/Oストリームのバッファ階層の操作で満足するのではなくて
ioctlレヴェルの働きかけで掃き出し操作を保証を行うべき、(デバイスによってやるべきことが違う
というわけで論理的思考う能力に乏しい香具師がfflush()万能教にはまっている悪寒、
ていうかそもそも馬鹿でかいバッファを用意しておいてから停電を恐れるというのはアレな発想でありまして、 真に停電に備えたいなら馬鹿でかいバッファを備えたデータのストリームとは別に、 どこまで書き込みが終わったかというだけの小さいサイズのジャーナル情報を こまめに書くというのがファイナルアンサーであって 停電の際はジャーナル情報だけ保証して停電の瞬間に馬鹿でかいバッファ上にあったデータは諦めるのが正しいシステム 停電による処理中データの喪失がどうしても嫌ということなら速度の方を諦めてアンバッファーにするかバッファを小さくしてくだち、
まとめ: この地球上のどこを探しても停電への備えがこまめなfflush()(笑)ということはありえない
小さいサイズでもそれが即座に反映だれるとは限らないけどな 停電に備えるならUPSだろ 何がこまめに書くのがファイナルアンサーだよ 突然の電源断で書き込み先のデバイスが壊れる可能性だってあるんだからな
粗悪なUPS使って電源破損した事あるから良い印象ないな
FFTで2^(2^34)-1を計算するやつの倍速化したやつをさらに倍速化したった……!
■ オリジナル
https://ideone.com/xSaa6x 2200秒
■ C++書き換え版
https://ideone.com/oDgjXr 2200秒
■ 倍速化
https://ideone.com/xHSzFD 962秒
■ ブロック6-step algorithm適用
https://ideone.com/rFCMy5 909秒 (倍速化版の94%) --- OpenMP無効、シングルスレッド
596秒 (倍速化版の62%) --- OpenMP有効、8スレッド
なんかもうCPUの帯域全部使い切ってやったぜ、みたいな 達成感みある、 ただし実行時間の2/3ぐらいはファイルの書き出しに使われている模様orz OpenMP有効化の条件だと 2^(2^31)-1までは1分以内に出て、 以降はVS2019の分析ツールのCPU時間のグラフを眺める限り、 ファイル出力を覗く正味の計算時間は 2^(2^32)-1: 20秒 2^(2^33)-1: 不明(見てなかった) 2^(2^34)-1: 62秒 だったので、ファイル出力を除く正味の計算時間は多分3分ぐらい、
OpenMPは昨日始めたのでなんか間違ってるかもしれん……orz
行列の転置が8スレッド使って(2回目以降も)実行時間1/8にならない件について:
https://ideone.com/rFCMy5 のfftb6::transpose()のコードの書き方だと50%ぐらいにしか短縮されなんだ 。n_
つなみにVS2019でOpenMP有効にするには 「構成プロパティー」→「C/C++」→「言語」→「OpenMP のサポート」 で逝ける、
>>176 >何がこまめに書くのがファイナルアンサーだよ
NTFSの実装、、、
>突然の電源断で書き込み先のデバイスが壊れる可能性だってあるんだからな
しらそん
それはUPSを買う金もないのに停電とかを引き合いに出してきた香具師に言ってやってくだち
もちついて考えたら #pragma omp parallel for firstprivate(i, n1, n2, nb, JJ) for (pow_t j = JJ; j < JJ + nb; j++) { const pow_t src_idx = n2 * i + j; const pow_t dst_idx = n1 * j + i; dst[2 * dst_idx] = src[2 * src_idx]; // 実部 dst[2 * dst_idx + 1] = src[2 * src_idx + 1]; // 虚部 } と書いては見たがこのdst[]やsrc[]は実は生の配列ではなくてstd::vector<double>::iteratorなので 共用変数扱いになってスレッド間で排他がかかっているのかもしれん……orz firstprivate()指示句が(最適化後はポインタとはいえ)C++のオブジェクトを受け取れるかはわからんので parallel forの前にポインタに置き換えてポインタをfirstprivate()するのが無難鴨、 (同じことはsinテーブルpriroot::nth_root wについても言える)
並列処理に何でマルチスレッド使ってんだよ 昭和からタイムスリップしてきたのか?
>>187 この問題でasyncプログラミングがどうやってマルチスレッドに太刀打ちするのか教えて
教えてください C++で書かれたDLLがあります とあるCエクスポート関数を呼び出すと稀に Access Violation 0xc0000005 が発生することがありプロセスが異常終了してしまいます 幸いなことにこの関数は大した仕事をしておらず結果が得られなければそれで困ることもありません(結果が得られれば少し役に立つ程度です) なのでこの関数の失敗を握り潰したいのですが、C++ でアクセス違反を try-catch で握り潰すことはできるのでしょうか? それともアクセス違反は致命的なエラーなので必ずプロセス終了に至るのでしょうか?
>>190 > 幸いなことにこの関数は大した仕事をしておらず結果が得られなければそれで困ることもありません(結果が得られれば少し役に立つ程度です)
そんな関数なら空の関数に差し替えればいいんじゃね
>>193 ありがとうございます!
/EHa を付けたらキャッチできました!
いままでは /EHsc が指定されてましたのでオプションの意味の違いを調べてみます
DLLが例外出してるのをCで握り潰してるのが原因だろ
素人の質問でごめんなさい。(ここが一番関連ありそうだったので)
バイオインフォマティクスをやっているのですが、例えば主にC++で書かれたUnicycler (
https://github.com/rrwick/Unicycler )というソフトウェアでは、--threadsオプションで使用するスレッド数を指定できます。
デフォルトだとスレッド数8なのですが、仮にそれを1コアを使って実行した際はどのような挙動になるのでしょうか。
コア数<スレッド数なので失敗するかと思ったのですが、思いの他うまく実行できてしまいます。
一般的にこういう場合、並列 (parallel)処理ではなく並行 (concurrent)処理で、スレッドごとに時間を分けて同一コアで処理している、ということなのでしょうか・・・
>>197 > スレッドごとに時間を分けて同一コアで処理している、ということなのでしょうか
せやで。
OS がスケジューリングしてスレッドを交互に実行しとる。
コア数以上のスレッドに分けても実行速度が上がったりはしないよ。
コンテキスト切り替えのコストの分だけむしろ遅くなると思う。
>>198 なるほど、OS賢いですね。。
つまり1コアでやるときは複数スレッドの処理もできるけど、無難に1スレッドの処理にした方がむしろ速い、ということですね。
勉強になりました!ありがとうございます!
各スレッドがio待ちしてるかも知れんし、コア数より多くても早くなる場合もあるんじゃね gcc動かすときもコア数1.5倍位指定してる
調べてみたらコンテキストスイッチにもプロセスコントキストスイッチとスレッドコンテキストスイッチがあって、
後者の方がコストが格段に低いとありました。
この場合は同一プロセス中の複数スレッドで後者なので、
>>200 さんの言っていることもありますし、コア数よりスレッド数を少し多めに設定しても速くなるのかもしれませんね。
実験して確かめるのが一番かもですね。
まあ今の実装は大抵スレッドといいつつプロセスだったりするけどね
pythonでもマルチスレッドとマルチプロセッシングは別物だろが
そのへんは色んな論が合って今の主流がどうなってんのかよくわからん。 でも一度はプロセスを軽くする方向 (スレッドの実態をプロセスとする方向) になったというのは私も聞いたことがあるような気がする。 (BSD 系の話と混ざってるような気もする。 だいぶんうろ覚え。) プロセスを軽くするというよりは段階を分けるというか、 プロセスをスレッド的な範囲で使っている分にはスレッド程度の処理しかしないみたいな感じ。 ただ、それは最終的には管理コストが思ったより大きくてそれほど効果的ではないというオチじゃなかったっけ?
forkもCoWがあるからオーバーヘッド大したことないんだっけ?
>>206 誰に聞いたんだよw
てか、少しは疑うことを覚えた方がいいぞ
>>208 ソース出してみ
>>209 Copy on writeを使わない実装よりは大幅に軽いけどメモリー空間とかを準備しなくて済むスレッドよりは重いよ
>>205 そうだった。勘違いしてた。
pythonで流行りの並列処理をやろうとしたらマルチプロセスだった。何を言ってるのか わからねーと思うが(以下略)
>>199 ユニプロセッサでも例えばI/O待ちやユーザ入力待ちしている間にできることをやっとくんだよ
例えばシングルスレッドのみを利用のサーバーでも その中で非同期タスクを1万個動かしてクライアント同時接続1万個の処理が可能 ほとんどがネットワーク待ちとディスク待ちだから非同期ならばそれだけ同時に並行処理(≠並列処理)できる
もし同期プログラミングしか出来ないと その多数のクライアントを捌くためにスレッド数を増やすことで対応することになるが スレッドリソースを喰うため大きいためスレッド数を増やせず スレッドスイッチングも重いため圧倒的に不利となってしまう
ネットのサーバーは本質的にマルチタスクで たとえシングルで力技かましてても外から見て複数のタスクを同時にこなしている
1対1スレッドがマルチプロセッサ使えて実装が楽で悪いことないよね
>>216 それは初心者まで
普通は非同期に処理する
>>217 非同期のスレッドってどういうのを指すの?
マルチスレッドは基本的に非同期だけどな 必要に応じてミューテックスやシグナルで待ち合わせする
しかしまあどこかにライブラリを作ってる人がいるんだけど、その事実を認識できんプログラマというのはおるよな
ジャップにはOSS読んだり一次情報確認しにいく文化がそもそも無いからな
非同期プログラミングでは多くの言語でPromiseもしくはFutureと呼ばれる同じ概念の抽象化を用いて行なう
つまりこれから行われることを期待する未来の約束という抽象化したものに次々と託していくことで
プログラムコードの見かけ上の記述順とは異なり並行して非同期に複数のタスクが走ることで非常に効率的に実行
それらは一つのスレッド内で何十も何千も非同期に並行して動かすことが可能であるがマルチスレッドを使えばさらにそのコア数倍を動かせる
>>216 それだと効率が悪すぎてお子様向け
プログラマー目指してるんですが、C++やるなら03と11の両方勉強しておいた方がいいですか?
はて? C++11やればC++03もカバーしたことになるからC++11以降一択だよ 細かいことはコンパイルエラーが出てから考えればいいんだよ
今C++03の案件とかあるんかな あっても正直関わりたくないな
何を言うとるか 今憶えるべきはC++20に決まっとろうが
C++11を勉強しておけば良さそうですね 独習C++をやります ありがとうございました
c++11で書いたコードをC++20でコンパイルしようとしたらエラー出まくりんぐ 教えてエロい人
スマソ、C++11じゃなくてC++14だた vector<int> unkos; for each (auto unko in unkos) { } これがエラー出てコンパイル通らない 環境が壊れてるんかな? IDEはVS2022 17.2.4
C#かなんかと混ざってない? vector<int> unkos; for(auto unko : unkos) { }
しょっちゅうC++とC#往復するから頭おかしくなるな でもコードスニペットで自動的にfor each (auto unko in unkos)みたいな構文に補完されるんだよね てか以前までこれでビルド通ってたし VSのバグかな?
確認したけど.cppと.hで試してる C++17まではビルド通るけどC++20にするとエラーだわ
C++11 以前はもう忘れていいとは思うけど 以前と以降の違いは知ってた方が良いとも思う
for each inはmsvcの独自拡張らしいな
>>240 やっぱVS固有の話だったか
>>241 マジ
ただおま環かも
参照&とか、左辺値とか、moveとか、copyとか、体系的に学びたいんだけど、 その辺、いいKindle本ない? オススメない?
C++の書籍紙の本ばっかだよな ネット上のドキュメント漁れって事なんだろうけど
C++をclassの使えるCとしか使ってなくて(そんなに使ってない)、 んで参照&を使った左辺値?を見よう見真似で使ったんだけと、うまくいかなくて(結局ポインタを使った参照を使いました) あとRustの本読んだらmove、copyを知って、その概念はC++でもあるとどこかで見て、体系的に知りたいと思いました。 Webだと細切れなのでKindle本で読みたいと思います。 オライリーのEffective modern C++なんか適当でしょうか? でもKindleないんだよなぁ
kindleはないけど オライリーは公式に電子書籍あるよ
所有や共有の機能が欲しいなら shared_ptr 使えば良いだけだろ
>>234 こ、こんな裏技が((( ;゚Д゚)))
それはつまりinが予約語になっているってことでもあるのかな
いや、たしかにC++プロジェクトやぞ
数年前から使ってるVSプロジェクトではC++14→ビルド通る、C++17→ビルド通る、C++20→エラー
今新規で作ったVSプロジェクトではC++14→エラー、C++17→エラー、C++20→エラー
意味フすぎて漏れそう
https://docs.microsoft.com/ja-jp/cpp/dotnet/for-each-in?view=msvc-170 調べたらfor each構文は非推奨とは出てきたけど
ほならね、コードスニペットで非推奨の構文出すなやと言いたい
しかもそれでビルド通らねえ
まあVSアプデが原因っぽい感じするし、大人しく推奨の構文使うようにするよ
お騒がせしてスマソ
>>252 property String^ MyStringProperty;
みたいな構文見た時点で気づけよ...
>>254 両方使えるって書いてあるけど
> この非標準のキーワードは、C++/CLI プロジェクトと C++ ネイティブ プロジェクトの両方で使用できます。 ただし、これを使用することはお勧めしません。
>>246 「江添亮のC++入門」は比較的ハードルが低く基礎を理解できるように書かれてると思う。
(別途学習する前提で継承まわりをごっそりと省いたりしてるけど……)
元になった原稿は無料で公開されてて、 Markdown で書かれているので
適当なツールを使えば Kindle で読める形式にもできるんじゃないかな。
C++/CLIはC++20で見捨てられてるので強制的にC++17としてコンパイルされる 昔から使ってるvcxprojなら知らん間に追加のオプションつけてたり、今のVSで規定値が変わったりしてるだろうからビルドが通らないのもありうる。 ちょっとしたプログラムならwandboxとかでgcc/clang試してみてもいいんじゃない? MSVCは独自拡張とか、標準ライブラリでも新しいバージョンのものを先行実装してたりするよ
MSVC を使ってないからよう知らんけど拡張を抑制するオプションとかないの?
C++/CLI捨てられちゃうのか じゃあ今後C#とかとのグルーには何使えばいいの?
PCREやbregonig.dllなどのPerl互換正規表現ライブラリでは、日本の漢字と中国の汉字が同じ\p{Han}に一絡げにされてるから注意しなよ
www.mercari.com/jp/search/?keyword=hr400p
こういう安い中古チューナ買って、Coinyをスカパープレミアム放送のICカード化して、
スカパープレミアムのチャンネル全部見れるし、USB HDDに録画フリー。
【avoCADO】 Coiny card Part4【仮想通貨】
http://2chb.net/r/avi/1640762750/ 夏休みの自由研究の成果を今ここに発表するのぜ、
2^(2^34)-1を計算するプログラムを最終的にオリジナルの9.26倍高速化すた、
↓↓↓先週のやつ↓↓↓
■ V3: ブロック6-step algorithm適用
https://ideone.com/rFCMy5 実行時間全体: 389.157479 sec
計算時間のみ: 185.163833 sec
↓↓↓先週のやつの改良版↓↓↓
■ V3.1: ブロック6-step algorithm適用、parallel for粒度変更(粗くした)+workメモリサイズ調整
https://ideone.com/dFjPXf 実行時間全体: 349.057446 sec
計算時間のみ: 151.493976 sec
計算時間のみ比較でオリジナルの9.26倍速、
計測条件: CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz メモリ32 GB OS: Windows 10 Pro 64 bit コンパイラ: Visual Studio 2019でビルド(x64) OpenMP 有効(omp_get_max_threads() == 8) 計算結果は最後(2^(2^34)-1)のみ出力 (↑ソースコードのSAVE_ITM_RESULTマクロ定義をコメントアウト。元に戻せば前と同じになる。)
つなみに同じような調子で時間計測すると、(コードはV3.1のSHOW_CSM_TIMEを参照されたい、
■ V0: オリジナル
https://ideone.com/xSaa6x 実行時間全体: 1586.875607 sec
計算時間のみ: 1403.402228 sec
■ V1: C++書き換え版
https://ideone.com/oDgjXr (※ FIGとRADIXはそれぞれ5と100000に訂正
実行時間全体: 1611.894164 sec
計算時間のみ: 1421.579748 sec
■ V2: 倍速化(バッタフライ演算で書き直したやつ。OpenMP非使用
https://ideone.com/xHSzFD 実行時間全体: 622.790273 sec
計算時間のみ: 435.143622 sec
やったわ;;;
つまりV2はV0より3.23倍速く、V3.2はV0より9.26倍速いから2^8倍を達成したのであった、
じつはさらにL2キャッシュ利用帯域最大化版というのを作ってみたのやが
どうもV3と同等かやや遅くなるorz
■ V3.2: L2キャッシュ利用帯域最大化版
https://ideone.com/ig7PuU 実行時間全体: 399.591214 sec
計算時間のみ: 191.301385 sec
やっていることは、NをL2キャッシュサイズの1コア割り当て分の半分に収まる複素数の数、として、
巨大桁数のFFTを(2*N×N)桁のFFTに分解して個々の(2*N×N)桁のFFTを6-step algorithmで解いているのですだが
なんかコピーしつつ転置するの回数が増えるので速くならないみたい
あとV3.1が速かったりV3.2がEXPN_L2CHACHE_SZを18からいくら増やしてもそれ以上遅くならないのは
Intel(R) Smart CacheテクノロジーがL2キャッシュとL3キャッシュ間の帯域をうまいぐあいに有効活用してくれているっぽい
ここらになってくると詳細は調べようが無いので漏れもソフトウェアー呪術者にならざるおえない
内容に関係のないクソみたいな指摘しかできないお前らも大概終わってるけどな まあこんなとこじゃなくてブログとかSNSにまとめろよとは思う
ジジイだから周りのこととかスレの流れとか見えてないんだろう 前頭葉が加齢で萎縮して空気を読む能力が衰えたのかな
>>277 > 内容に関係のないクソみたいな指摘しかできない
ハァ?
文盲じゃなかったら本人だろコイツ
1の乗根じゃなくて整数環でFFTした方が誤差の意味でも速度の意味でも劇的に改善するって何度も指摘してるんだが
>>279 これ前スレからの流れなのか知らんかったわすまんな
どうりで批判が多いわけや
どうでもいい言葉尻に突っかかるやつ 若さを自慢したつもりになってるの? 尻の青さをバカにされてるだけだよ
プログラマの発言じゃないな プログラムは1文字のタイプミスで全く違う挙動になるのだから
偶によくC++読み書き出来ない奴がレスしてるんだけどどっから湧いてきてんの
いよいよ Java のクラスライブラリを C++ に移植しようと思っていますが、需要はありますか? そろそろ共通のクラスライブラリが確立されてもいいと思っているのですが、あまりそんな話がないのが不思議です
>>284 見せてもらおうか!!
◆QZaw55cn4c謹製ライブラリの性能とやらを!!
>>287 OO な各言語で名前と機能が共通するライブラリの必要性を痛切に感じているのです
提供されるクラスライブラリが共通であれば、各種言語の純粋な潜在的能力に応じた評価が可能となります
>>288 性能よりも、各言語で名前と機能の紐づけが共通することを優先します
Javaクラスどうこうよりもfinallyステートメントをどうするかなんでは
>>291 ああ、それ、ありましたね finally か、結構重たい課題ですね
>>282 template <typename T> を template <class T> と書いただけでジジイ呼ばわりするようなもんだぞ
誰もtypoの話なんかしてない
あ、1人だけいるのかw
? typename と書く方が文法的に新しいの?
>>295 いいえ。 少なくとも ISO の規格としては最初から有りますし (型引数のところに書く分には) 機能的な差もないです。
だから、
>>294 は単なる表記の揺らぎにすぎない (どちらが間違いというものでもない) 例として出しているんだと思います。
>>295 CでC89以前にK&R Cがあったように
C++でもC++98以前にARM C++があった
ISO限定で言うと餃子の言うようになるが
もっと遡るとtypenameは後からできたもので
ARM C++では<class T>という書き方しかできなかった
三十年くらい前にC++primerだったかな? 「typenameとclassならclassのほうで書いとけ、 なぜならタイプ数が少ないから」 みたいに書いてるところがあって(半分ジョークなんだろうな) 最初にそれで刷り込まれてるからclassでしか書いたことない
C++ってstaticメソッド継承されますっけ? Parent.Hoge()ってChild.Hoge()としても呼べます? あるスクリプト言語を使ってた時にどうやら継承されてなかったようで、言語ごとに違うのか気になりました
型引数は class と書いてあってもクラスに分類されない型 (スカラ型など) を受け取れるのでなんか変な気分ではあるな……。 それでも私は class キーワード派だけど。
modern C++ designの著者は、ユーザー定義型のみを想定してる場合はclass, 組み込み型も想定してる場合はtypenameにしてると書いてたな
>>300 private とか protected とか知ってるか
private踏んだりしたらエラーメッセージ見れば済む話だと思うが class継承のときのpublicつけ忘れでprivate扱いになるのはやらかしてそう class C{ public: static void f(){} }; class D : public C{}; int main(){D::f();}
>>307 class継承のpublic忘れるとエラーになるよと言う話
2箇所あるpublicのどっちか消してみなよ
>>309 staticもつけ忘れたのか
どんくさいなお前
>>279 数論変換はしばし待たれよ卿、
NTT有名素数modとしてよく使われるのは
998244353 = 2^23 * 119 + 1
やそうやがこれ単独では2^23桁で表せる数値までの計算しかできないことは確定的に明らか
10^5進数表記をとったとして2^(2^34)-1はで表して
1034331189 > 2^29 桁 >> 2^23桁
なのでストレートにやるとしたら足りないのであっる
一方Six-step algorithmを導入したらば2^15桁までのFFTで済むから、NTT化が射程に入ってくる
というわけで漏れは天才の判断としてまず1の累乗根のFFT×Six-step algorithmを
OpenMPで激速化することを極めんとしているわけや;;;
それと
>>279 の口ぶりでは数論変換にしたら桁違いに早くなるみたいに読めるが
double同士の掛け算2^15回分が
int64同士の掛け算2^15回分に高速化される程度であって現行のレコード145 秒が100 秒切れるようになるか
っていうとビミョー
はい論破、
>>302 の行間に書いてある通り、型引数意外の状況でだがtypenameキーワードが必要なケースが存在する
ていうかこれ↓
https://faithandbrave.hateblo.jp/entry/20080129/1201597743 逆に言うと
それ以外ならclassでええやん、、、
アンカーミスったorz
誤:
>>302 正:
>>296 >>314 なんできゅうにそこのtypenameの話しだすの?
単に型パラメータんとこの話をずっとしてたんやないん今まで
>>300 >C++ってstaticメソッド継承されますっけ?
継承と言うか「可視」ではある。
>Parent.Hoge()ってChild.Hoge()としても呼べます?
staticメンバを参照したい場合は、インスタンス・メンバとは書き方が違って、
Parent::Hoge() や Child::Hoge()
と書く。
でも微妙だな、Child::Hoge()で呼び出せるかどうか、実験の必要はある。
インスタンスからも static メソッドは呼び出せるよ
https://ideone.com/tpA9jy C++コンパイラっていつからconst char*型引数がbool型引数に暗黙変換されるようになったんだ? 以下のような内容が警告なしでコンパイルできてしまうんだが int foo(bool bar); const char* ptr = "test"; foo(ptr);
スカラ型がboolに暗黙変換できるのは太古から変わってない int (*p)(bool) = foo; std::cout << foo; //出力は「1」だがfooが1番地から開始ということではない
みなさまこんにちわ! 暑い日が続きますが質問させてください。 namespace hoge { class foo { public; void set(class member_ptr* arg){ptr=arg;} private; class member_ptr* ptr=nullptr; }; } という名前空間を作成し、それをmember_ptrが定義されているソース(およびヘッダー)ファイルで使用したいです。 ところがmember_ptr*をset()に渡したとき、「hoge::member_ptr*は member_ptr*と互換性がありません」というエラーが出てしまいsます。 名前空間をはずすorポインタ関連の記述をコメントアウトさせると普通に動作するので、大まかなコード自体は問題ないと思うのですが…… リインタプリットキャストも出来ず困り果てておりますが、名前空間内部のメンバにポインタは持たせない方がいいのでしょうか? それとも名前空間での不完全クラスでの定義がまずいんでしょうか? ほとほと困り果てております。 わかる方がいらっしゃいましたらお教えいただけれう゛ぁ…… 先感謝!
>>330 問題が再現するコードを提示してください。
どっかで namespace hoge{ class member_ptr; } class member_ptr; みたいなことやってるような気がする 前方宣言(か実体定義)が別の名前空間にあって、同じclassを見てるつもりで別のclassを見ているだけじゃない?
>>331 長文になってしまいますがお許しください。
───────────────
//ptr.h
class ptr
{
public:
ptr(int arg) { a = arg; }
int a = 0;
};
───────────────
//Test.h
namespace Test {
class innerTest
{
public:
class ptr* get_mPtr();
private:
class ptr* mPtr;
};
}
───────────────
//Test.cpp
#include "Test.h"
#include "ptr.h"
ptr* Test::innerTest::get_mPtr()
{
return nullptr;
}
//↑この定義部分で「宣言に互換性がありません」というエラーが出てしまいます
>>334 class キーワードを付けた場合にはクラスの宣言を同時にしたものとみなされる。
つまり class ptr* get_mPtr(); と class ptr* mPtr; は「このスコープで」 ptr を宣言したかのように扱われる。
もちろん実際には innerTest の中では ptr の定義はないので不完全型のままだが、
この ptr は Test::innerTest::ptr のつもりで解釈されてる。
グローバル空間で定義している ptr とは別物なので別物というエラーになるわけ。
class ptr; namespace Test { ...
Cのstructと同じ感覚でclassって書いちゃってるのかこれ
>>335 !336,338
ありがとうございます!
おっしゃる通りに名前空間の外で前方宣言し、ソース部分で定義したらうまくいきました!
特に理由がない限り、名前空間内部で定義してはいけない(戒め)
ありがとうございました!
VB.NETからバイナリをC++(JNI)に渡して受け取ったバイナリをJavaに渡したいんですけど、C++で受け取ったBYTEをjobjectに変換する方法が分かりません。 どなたかご存知でしょうか。
C++勉強中です。ムーブコンストラクタについて教えてください。 ムーブコンストラクタは、要はムーブ元の指すポインタをムーブ先に変更しているだけだと思います。 これはconstなしコンストラクタでも実現できると思いますが、意図を明示するためにコンストラクタが分かれていると思っていいですか? また、ムーブコンストラクタの仮引数が右辺値参照になっている(std::moveした右辺値を渡す)理由がよく分からないのですが、これは決まり文句として覚えるしかないでしょうか?
>>343 まさにその発想で作られたauto_ptrとかいうスマポ(廃止済み)がとんでもねえゴミカスだったから
その教訓でコピーとムーブが分けられたんだよ
ムーブって、所有者が移転してると考えた方が 場所なんてどうでもいいでしょう
>>343 右辺値は大抵の場合に一時オブジェクトだからどうせすぐに破棄される。
後で別の場所で使うということがないと期待できるから内容を移動してしまっても問題にならないんだ。
だから右辺値を入力とするときは原則としてムーブ扱いにする。
多分、右辺値参照イコールmoveと覚えてしまってるのでは? C++11より前は一時オブジェクトとそうでないものを文法上区別することが出来なかったのよ moveはあくまでキャストに過ぎない、一時オブジェクトでないものを一時オブジェクト扱いにしてるだけ
一時オブジェクトにキャストしてすぐ破棄されるようにしたと言っても、 右辺値参照に代入しているのでヌルポインタにするまでは使い続けられますよね そもそもstd::moveで一時オブジェクトにキャスト、これを右辺値参照で束縛して有効期間を延ばす…って 初めから普通の変数を使えばいいのでは?と思ってしまいました ムーブを表すための仕組みとして&&とstd::moveの組み合わせが追加されたということなんでしょうかね
>>348 結局そのあたりも含めてC++で複雑化した様々な点を全てシンプルに綺麗に整理し直して分かりやすくした言語が望まれてRustが登場したんだろうね
>>348 なんだかその文面からは仕組みを理解しているようには見えない。
>>348 何を言いたいのか全然わからない (仕組みを間違って理解しているか用語が誤っているかしている) ので
もうちょっと具体的に実例か何かで示してみて。
教科書の言葉適当に並べて分かったふりしてる感がすごい
ムーブは「所有権」をムーブさせるものなので、所有権という概念がないと理解できん
>>349 引数渡しのデフォルトをmoveにしているのは失敗だと思うけどな。
性能優先でそうしたんだと思うけど、そういった技術的説明無いから設計ミスにしか見えない。
>>354 あれは大正解
実際に色々なプログラミングをするとよくわかってくる
Rustは上手く設計されていることがわかる
右辺値参照って概念的に難しいよね そもそも右辺値とはなんぞやというところから、一時オブジェクトの生成とそれが破棄されるまでのコンパイラ側の仕組みを的確に理解する必要がある こんなのよく思いついたなと感心はするけどw
テンプレート関数で頻繁に出現する=演算子コピーによるオーバーヘッドを減らす必要に迫られただけの話ジャマイカ?
>>353 「所有権」って言っちゃうと誤解を生むような気がする
実体としてはデストラクタを呼ぶ権利だよね
インスタンス自体は(通常)スタック上に確保されているので、その所有権の移動まではできない
だからこそ「参照」なんだけども
デストラクタを呼ぶ権利だなんてお前も理解してないだろ
>>355 移譲にした方が嬉しい例を示してくれ。
C++なら引数渡ししてもオブジェクトは手元に残るのが常識だから、Rustがわざわざ移譲デフォルトにしているのは違和感しかない。実際、Rust習得の最初の難関が移譲だし。
>>360 本当は「所有権」じゃなくて「管理責任」だからな。スマートポインタとか所有していないリソースの管理とかやらされるし。
>>362 移譲という概念はない
C/C++もRustも同じで&を付けて&varnameの形で渡せば参照渡しとなる
同じ形なので全く違和感はない
所有権を手放さないで渡すには参照渡ししかないのだからその場合は&を付ければよい
もちろんプログラミング言語によって異なる部分もあるのは当然
そんな些細なことを違和感と言うのは極少数の類似言語しか知らないと言ってるようなもの
まあ所有権というよりは「後始末をする義務」だよな 日常的にポイ捨てしてるモラルの低い人間にはピンとこないかもしれない
誰が持ってるかわからんよりは、絶対渡すと決めたほうが安全な気はする
>>362 それは非常にシンプルで突き詰めれば値渡しと参照渡しの2つしかないところを『参照渡し』は結局ポインタを渡せばよくC/C++/Rust揃って「&変数名」表記 もう一つの『値渡し』のところで少し考えるべきことが出てくる 大きく分けて二つに分かれる (A) 数値型など値をコピーして渡しても問題なくコストも安い型の場合 (B) ヒープに確保した領域など値をコピーして渡すのはコストも高い型の場合 ここで後者(B)のケースは所有権すなわちメモリ解放責任も関わってくる Rustでは (A)タイプの型の場合はコピーして渡す →コピー可能な型は所有権なし (B)タイプの型の場合はムーブして渡す →所有権(解放責任)が移動する もし(B)タイプの型で所有権を保持したまま渡したいならば (1) 参照渡しをする (2) コストがかかってもよいから明示的にコピー(clone)して渡す の2通りとなる つまり (3) 所有権をムーブする と合わせて3通りの渡し方が存在する 最初の問題に戻ると 渡し方の表記「&変数名」と&を付けない「変数名」の二つある表記法を (1)(2)(3)の3通りのどれに割り当てるかという問題に帰着する 「(1)参照渡し」はC/C++と同じく「&変数名」と記述 そして残る&を付けない「変数名」のみの表記をコストが低い「(3)所有権ムーブ」とした ちなみにコストが大きくかかる「(2)コピー(clone)」はcloneした時点で別物となり新たな別の所有権(解放責任)が生じているため専用の表記方法は必要ないが強いて式として書けば「変数名.clone()」となる これはlet x = 変数名.clone(); としておいて「x」とだけ表記して渡すのと同じ つまり新たに生まれたxをムーブするのと同じになり表記に一貫性がある 以上の理由によりRustでの引数などの渡し方の表記方法は上述のようになっている 理解してから質問させてもらったつもりなんですが、まだ全然だったようです 確かに所有権という概念を理解していません 勉強してから出直します ありがとうございました
>>367 というより、コードが実際にどういう動作になるかがわかってない感じ(それこそC言語レベルの基本のところ)
もっと書いて実験した方がいいよ
move の挙動を「C言語レベルの基本の」サンプルコードで理解できたら画期的だなあ笑
エアプだろお前ら
>>348 辺りから読み直せ
一時オブジェクトの破棄とか裏で何が起こるかの超基本が理解できてないから
あくまで文法上のことに過ぎないmoveと破棄をごっちゃにしてると言ってる
所有権ってデストラクタで破棄する義務を負う、権利とは名ばかりな概念でしょ
自分から破棄しない限りはアクセスできることが保証されるから権利ではあるな
エナジーボンボンはCodeVeinに出てくる赤い玉だったんだよ
>>376 他からアクセスできることが保証されなければバグってすべておじゃんなのだから
>>376 の権利は有難がっても仕方が無い
=std::numeric_limits<decltype(ほんそれ)>::max()
condition_variableってなんでわざわざmutexと一緒に定義しないといけないの面倒でしかたないんだけど。 しかもへんてこな目覚めがあるなんてバグを平然と放置してるし。 win32のSetEvent()のほうが俄然使いやすいんだけど。
mutex は排他の仕組みであって同期の仕組みと分離する思想なんじゃないかなぁ……。 あんまりイケてないとは思うけど。
それはOSの問題なうえ、充分合理的な動作と認められている。
へんてこな目覚めはなんで生じるのかは知らんなんか深い理由でもあるんじゃないのJK それはおくとして、両者にはキューイングの思想の違いがまずありき、 [1] WindowsのSetEvent()はイベント発生をキューイングし、待機中スレッドをキューイングしない [2] 条件変数はイベント発生をキューイングせず、待機中スレッドをキューイングする これでかなりイベント発生と待機の組み合わせの性格の違いが出る。 [1]は待機中スレッドが無くともイベントをセットでき、その後最初に待ちに入ったスレッド1個が待ち解除される [2]は待機中スレッドが無いとイベントが無視されるが、通知方法をnotify_one()だけでなくnotify_all()も選べる [1]はWaitForMultipleObject()により1箇所の待機で複数種類のイベントを待ち受けられる(μITRONのイベントフラグ的な使い方ができる が、[2]でそれをやろうとするとあるイベントでスレッドを起こしたら、そのスレッドの待機中スレッドとしてのキューイングを 他のイベントついてもクリアせねばならない、みたいな余計な処理が必要で効率的に実装できない ということは、条件変数でWaitForMultipleObject()的なことをやろうとしたら、イベント要因を別途変数にセットして 待機中スレッドに伝える必要があり、この変数の操作→イベント待ち解除→解除されたスレッドが変数を参照、 というのをatomicにやらざるおえないから、ミューテックスのブロック内でイベントの待機とセットを行わねばならない仕様に、 なったと思う
それ隠蔽できるだろうけど、条件変数の基本要素がそれなんだからそういうもんです。
しかしまあ普通にスレッドの中にイベント待ちを作ったら、 イベント要因は (1) 本来のイベントの意味(複数かもしれん (2) スレッド終了 の2種類は必ず生じるけどこのために2種類以上のイベントオブジェクトを設けてWaitForMultipleObject()で待機するのは アフォらしいので結局条件変数的に、イベントオブジェクトは1個、イベント要因を表す変数が1個、みたいな形になって 条件変数と同じようなしくみに落ち着く 、希ガス (ただしイベントオブジェクトとイベントを待つスレッドの実体が完全に1対1ならミューテックスによるガードは不要
mutexないとあっちのスレッドが条件変えちゃうのでは
イベント要因が3種類以上とかイベント発生と待機解除が必ず1対1でなければならない、みたいなケースを含むちょう一般論で言うとそうかorz
>>388 >イベントオブジェクトは1個、イベント要因を表す変数が1個
その方がめんどくせえわ
>>383 condition_variableの引数にmutexのロックがあるおかげで休眠処理を(1-1)〜(1-5)のようにできる
(1-1)mutexでロックして、(1-2)起動条件を設定して、(1-3)起動条件のチェックをしてから、(1-4)休眠して、(1-5)ロックを解除
もしそういう仕組みが無いとこんな感じになるかな
(2-1)mutexでロックして、(2-2)起動条件を設定して、(2-3)ロックを解除して、(2-4)起動条件のチェックをしてから、(2-5)休眠する
休眠を起こす方は、(1)mutexでロックして、(2)起動条件を設定して、(3)起動して、(4)ロックを解除、となるわけだけど、
(2-1)〜(2-5)の場合、(2-4)の後(2-5)の前に(1)〜(4)が動くことができて、その場合に永遠に休眠する場合がある
(1-1)〜(1-5)ならそういう問題が無い
バトン持ってるやつが偉いというのはいいとして、バトンを途切れなく渡すための仕組みが要るんじゃ
>>383 実際まあ面倒くさいよな。
最近は後で書き直すつもりでとりあえずスピンしてatomic_bool待つコード書いてしまってるわ
>>388 >>392 ご回答ありがとうございます。
かなりお詳しい方とお見受けします。
ご回答いただいてから、何回も読み直してしますが
いまいち理解できていない状況です。
そういうものとして、コーディングすれば別に支支障はないのですが、御二方のように完璧に理解したいと勉強しております。
また質問させて頂くかもしれませんが、その際はよろしくお願い申し上げます。
以上
基底クラスのprivateメンバと、private継承された基底クラスのpublicメンバって派生クラスから見たら同じじゃないんでしょうか? 前者は派生クラスからアクセス不可で、後者は派生クラスからアクセス可能なようです というとこは意味が違うんでしょうが調べでもよく分かりませんでした どなたか教えてください
public/privateは、自分よりも外側からのアクセスを許可するかの指定。 class B{ private: int b1; public: int b2; }; class C: private B{}; int main(){ B b; C c; } b.b2はアクセス可能。c.b2はアクセス不可能。 class C内からは元々publicだったthis->b2のアクセスに制限はない。
>>397 class Bをprivate継承したことで、b2はclass Cのprivateメンバになるということですね
理解しました、ありがとうございました
>>398 需要なさそうなC++の派生みたい。
人気が出てきたらスレを分けよう。
通常のキャストと参照へのキャストの違いを教えてください。 #include <iostream> class Base {}; class Derived : public Base {}; int main() { Derived d; Base& b1 = static_cast<Base&>(d); //@ Base& b2 = static_cast<Base>(d); //A } このようなとき、@だとコンパイルOK、Aだとコンパイルエラーになります。 どのような違いがあるのでしょうか?
>>401 キャストが原因でコンパイルエラーが出てるわけではないです
簡単に言うと②の右辺は rvalue なので非 const lvalue に束縛できません
>>401 値へのキャストは、一時オブジェクトを作り必要ならコンストラクタを実行する
参照へのキャストは、一時オブジェクトを作らない
ただしconst修飾された参照と右辺値参照の場合はこの限りでない
具体例で言うとこれ↓はアリってこと。 #include <iostream> class Base {}; class Derived : public Base {}; int main() { Derived d; Base&& b3 = static_cast<Base>(d); const Base& b4 = static_cast<Base>(d); } 注意点として、 本来なら一時オブジェクトは式の終わりに解体されるので参照が無効になりそうなもんだが 参照で受けている場合はその参照の寿命と同じ分だけ延命される特例がある。
俺が言ったのはこれのこと struct base { base(int); }; int main() { static_cast<base const&>(1); static_cast<base&&>(1); }
コンストラクタの最適化(によるコンストラクタ呼び出し自体を削除)は コピコンだけが適用?
じゃあ
>>406 のコードでは
コンストラクタの呼び出しだけは保証されて、
その後のコピーやムーブは保証されない動きになる?
そもそも406のコードにコピーもムーブも一つも出てきてないけど
・フリーランスに立ちはだかる「常駐」の壁。慣例を打ち壊し、 “テレワーク”案件3割→8割へと成長を遂げた「クラウドテック」の軌跡 ・リモートワーク求人専門サイト「プロリモート」がリニューアルオープン、 業務委託契約の求職者と企業をマッチング ・1/3以上が採用につながる高マッチング率、リモートワーク×エンジニア・デザイナー専門の 人材紹介サービス「ReworkerAgent」正式リリース場所からも時間からも自由な働き方を実現! ・『ReWorks(リワークス)』リモートワーク特化型転職サイトとして 3月5日 リニューアル ・副業・兼業マッチングサービス「クラウドリンクス」登録者数2万人突破 中小企業で進む副業人材の採用、96%が継続採用を希望 ・フリーランスが活用できる「最大1,000〜3,000万円・補助率50%〜75%」の 『ものづくり・商業・サービス補助金』とは?概要や条件を解説 ・茨城県日立市、県外からの「テレワーク移住者」に最大151万円の助成金 ・長野市、市内に移転・事業所設置し、移住することで最大550万円の支援金を支給
練習でオブジェクトデータベースもどき を書いたらGITHUBに送ったのになんか反映されない。 がーん!!
コンストラクタって本当に戻り値無いんですか? 例えば MyClass c = MyClass(); としたとき、cにはMyClassのコンストラクタで生成されたインスタンスが格納されます 戻り値が無いのになぜそうなるのでしょうか?
>>414 それは明示的な型変換 (関数記法) という規則で示されている。
https://timsong-cpp.github.io/cppwp/n3337/expr.type.conv 見かけ上は普通の関数呼出しと区別がつかない記法を使うけれど関数呼出しではない。
クラス名を関数風に使ったらコンストラクタで構築したオブジェクトを (あたかも関数の返却値のように) 返すことになっているというだけなんで、
まあそういう仕様なのだと覚えてもらうしかしょうがない。
コンストラクタは特別な地位にあって色々と特別な規則があるんよ。
>>415 ありがとうございます
そういう仕様だと覚えることにします
ついでで申し訳ないんですが、コンストラクタと明示的な型変換って同じものなんですか?
MyClassA a;
MyClassB b = MyClassB(a);
としたとき、コンストラクタはMyClassBの関数ですが、明示的な型変換はa(MyClassA)の関数ですよね?
>>416 > コンストラクタと明示的な型変換って同じものなんですか?
違う。 明示的な型変換を試みた結果としてコンストラクタが呼び出されたりもするということ。
> コンストラクタはMyClassBの関数ですが
MyClassB のメンバ関数の意かな?
> 明示的な型変換はa(MyClassA)の関数ですよね?
何がいいたいのかわからない。
MyClassB と書いてあるのに何故か MyClassA のなんらかのメンバ関数が呼ばれると思っているということ?
どうしてそう思ったのかもうちょっと詳しく説明してみて。
>> 417 class MyClassB {}; class MyClassA { public: operator MyClassB() const { return MyClassB(); } }; int main() { MyClassA a; MyClassB b = MyClassB(a); } このようなとき、型変換で呼ばれるのはMyClassAのメンバ関数であるoperator MyClassBですよね? MyClassBのメンバ関数であるコンストラクタを呼び出しているのと見分けがつかないので、疑問に思いました
explicit指定してなけらば代入はコンストラクタに渡される
>>418 ユーザー定義変換演算子があればそれが使われたりもすることもある。
どの状況で何が呼ばれるのかは複雑な解決規則があって、どちらかが優先になることもあれば曖昧 (エラー) になることもある。
この場合にどうなってるのか仕様を辿ってみたんだが、
MyClassB(a) は C スタイルのキャストと等しいので (MyClassB)a と同等、
そしてこれは static_cast<MyClassB>(a) と同等と解釈される。
このとき MyClassB temp(a) と宣言したときのように初期化された架空の変数 temp の値が返される。
そういうルールだった。
MyClassB temp(a) と宣言したときに MyClassB が MyClassA を受け取るコンストラクタを持っていれば
それが呼ばれる (この場合はそのようなコンストラクタはないので呼ばれない) し、
そうでないなら暗黙の型変換が実施されるので MyClassA::operator MyClassB が呼ばれてから初期化される。
職業としてc++を使用してる人に聞きたいんだけど 設計者がどう動作するか分かってないコードが含まれる製品が出荷されてるのっておかしくない? しかもその担当は、俺あんまりパソコン得意じゃないって。 そんな人間が書いてるソフトをお金を出して買ってくださってるお客様に言えるかよ、馬鹿なのかな
まあ売る方も買う方も承知でやってる互助会みたいな世界もあるから
自社製品のすべてをわかっている事業者なんてないよ もしものためにお客様相談窓口あるわけだし
>>423 そう言うことではない。
では、あなたに聞きたい
車を買いに行って、ディーラーの人に「このボタンなんですか?」と質問して「押してみないと分からない」なんて答えたらどう思いますか?
ディーラーが設計してるわけではないことくらい誰でも知ってるけど、ここで買っていいのか?って思いませんか?
>>421 C++使いはPCのパワーユーザーとは限らんよ
それにPCだって無数の技術が詰め込まれていて
たとえるなら1つの大学のようなもので
迂闊に「俺はものすごくPCに詳しいんだ!」なんて言うと
ほぼ100%恥かくしな
>>424 外部仕様と内部仕様の区別もつかないボンクラ乙w
つかC++関係無くね どの工程にでも言える話をここでされても困るんだけど
まず
>>421 がC++との関連を示すべき。それ以外のところで話を広げても不毛。
>>420 解決規則が知りたいと思ったのですが状況によって難しそうですね
混乱してきたので整理して考え直します
ありがとうございました
>>428 マジで言ってるならもう少し勉強してきた方がいい
ボタンの操作とかのように取説に載ってるのは外部仕様
>>421 はそういう話じゃない
原理はわからなくてもテストちゃんとしとけばいいという世界もある
windows作ってる開発者や営業にメモ帳のショートカット全部言えるか聞いてみればいいんじゃね? 外部仕様すら知らんの?馬鹿なのかなって
「メモ帳のショートカットを言え」がなんのことやらわからない。
最大限にエスパー能力を発揮してアクロバティックに解釈するとテキスト形式のファイルのことではないかと思う。 デフォルトだとメモ帳に関連付けられているからテキスト=メモ帳という認識が出来上がる可能性はある。
関連付けされた拡張子の話をしてるのかな? それでもあとからインストールされたものでコロコロ変わるから、意味不明だな。
メモ帳はnotepad.exe、ショートカットはキーボードショートカットの意味だがそれすら想像つかないなんてずいぶん頭が悪いな パソコン得意じゃないのはお前のことじゃん
>>436 Windowsのショートカットはそういう意味じゃない。
>>438 そんなのわかっているが、彼の略語が自分にしかわからないから問題にしている。
>>438 メモ帳にショートカットキーは割り当てられていない。
メモ帳を起動する方法の種類を言っているんだろう。
自分のPCの設定をデフォルト設定だと思っているジジイだろうな
争いが起きるのは霊的な問題もあると思うんですよね。 先日亡くなられた安倍元総理も生前大切にされていた霊験あらたかな壺があるそうなんですよ。 ただ、とても値が張るそうで、安いものでも3000万を下らないそうなんです。 そこで、5ch有志でお金を出し合って共同で購入しませんか? そうすればスレも安定すると思うんです。
Windowsのファイルの種類のひとつが「ショートカット」というのがわからなくなって、Windowsそのもののことがわからないのに知ったかぶりで物を言う認知症のじいさんなんだろ。
おまえら全員Windows板行って二度と帰ってくんな
>>432 そらで全部言える必要ないだろ
開発者なら外部仕様にアクセスできるだろうから一覧くれって言えば出すことはできるだろ
メモ帳にショートカットキーがあるという架空の設定で話していてもよくわからない。
F5で現在時刻入力とかCtrl+Gで行番号指定ジャンプとかCtrl+-/+/0で縮小・拡大・元に戻すとかの メモ帳のキーバインドのことなんじゃないのどうでもいいけど
>>449 メモ帳そのもののことを言っていたわけか。メモ帳を使っている人間がどれだけいるのか疑問だけど。
というか、あれってエディットコントロールの機能ですよね エディットコントロールのソースってどっかでみることが出来ますかね?
Windows のソースコードは一部の政府機関や学術機関と契約を結んで提供している事例はあるが、 個人で見せてもらえるようなもんじゃないよ。 あえて言うなら ReactOS (Windows 互換の OS を目指すオープンソースプロジェクト) が参考になるかもね。
>>415 MyClass a();
MyClass & b = MyClass();
const MyClass & c = MyClass();
MyClass d = MyClass(); ← コピーコンストラクタ発動?
それともムーブ?
>>421 javascriptやelectronやphpやvb/vbaの方が判ってない人が描いてる確率は高い
>>449 最近覚えたのは Win+G ですね判ります
>>449-450 ああそれで
「押してみないと判らない」
って話が出て来たのか
普通の人間なら闇雲に押すんじゃなくて
押す前にマニュアルやヘルプファイル読むだろうな
GUIでキー操作というのは矛盾も含んでいるんだけどな
>>454 基本的にはムーブコンストラクタが呼ばれる場面なんだけど……。
一定の条件でコピーやムーブを省略 (Copy elision) してよい場合がある。
MyClass d = MyClass();
はその条件にあてはまるので
MyClass d();
と同じ挙動になることがある。 (コピーもムーブも起こらない。)
省略が許される場合の一部が C++17 以降では省略が必須に変更された。
また、 C++17 以降で省略が必須のときはコピーコンストラクタもムーブコンストラクタも存在しなくてよい。
故に以下↓のような例は C++14 ではエラーだが C++17 では通る。
struct MyClass {
MyClass(const MyClass &) = delete;
MyClass(void) = default;
};
int main(void){
MyClass d = MyClass();
}
むかしまだMacOSが漢字TalkだったころにMacキチガイの知りあいが 「Windowsなんて駄目だよ、だいたいマウスにボタンが2つあるみたいなシンプルさを欠く設計な上に なにかとキーボードを併用しないといけない、GUIとして未完成といわざるをえない(キリッ」とかいいながら Macでマウスボタンとコマンドキーやらシフトキーのコンビネーションをものすごい熟練の手付きで操作していたのが印象的だった
windows10でスタートメニューを非表示にしたいのですが良い方法ないですかね? スタートメニューのHandleを取れれば良いのですが、、。 ネットでいろいろ調べましたが見つけたサンプルコードは、windows10では動きませんでした。
以下のプログラムを実行したとき、変数xとyが初期化されるのはどういう理屈ですか? class myClass { public: int x; int y; }; int main() { myClass c{ 100, 200 }; } 暗黙のコンストラクタで代入されているのかと思いましたが、 xとyをprivateにするとコンパイルエラーになるので違うようです。 インスタンス生成の{}を()に変えるとコンパイルできなくなるのでそれもどうしてか知りたいです。
struct myClass { int x; int y; }; int main() { struct myClass c = { 100, 200 }; } と同じ理屈じゃね?
C言語からやってないと構造体の初期化は理解出来んだろうな
trivial ctorじゃ説明つかないからなaggregateは
建増しでやってきた言語だからしょうがないけど初期化の方法がやたらいっぱいあって混乱する
>>465 集成体初期化 (Aggregate Initilization) に該当する。
クラスが一定の条件を満たしたときに集成体の扱いになる。
文法表記を似せているだけの別物と思った方がいいかも。
ちなみに C++20 からは丸括弧でも集成体初期化が出来るようになってるよ。
>>466-467 ,
>>471 ありがとうございます
C言語の構造体の初期化と同じですね
後方互換を保つために残してるような気がしました
コンストラクタ定義が無いときしか使えないんですね
皆さんにお聞きしたいんですけど inline展開しまくることによる弊害って主になんでしょうか?
もうデメリットはなくなって来たな 実際のコンパイラもデフォでinlineぽい動きするし ただの開いたサブルーチンというだけでなく定義の統合がありがたい
デバッグが面倒臭くならない? そうだあれか リバエンし難くする効果があるとか
インライン展開するとスタックトレースで関数名が出なくなりますか?
>>478 コンパイラにもよると思うけど
おそらく出なくなると思います!
c++ってまだまだ需要あると思いますか? 私はあるかなと思うんですけど...意見ください。
何年も前だがインライン展開の基準を指定する GCC のオプションで めちゃクソに緩めの数値を指定 (つまりインライン展開されまくる) して ベンチマークをとった記事が話題になったような覚えがある。 結論を覚えてないし、どこで見たのかも覚えていないので役に立たん話ですまぬ。
>>481 C++は需要が減り衰退していく
昔はともかく現代の視点からは、設計が悪くそこへ建て増しを繰り返しているため、言語として劣っていて使いにくい
そのため次第に既存システムの保守がメインの言語となっていっているが、それさえGoogleの発表したCarbonのような言語の方がプログラマーにとってもありがたい
もちろんそのCarbonでさえそのFAQにこれはあくまでも既存の保守用の言語でと書かれている
設計思想のないバカがさわるとえらいことになる言語だからな
>設計が悪くそこへ建て増しを繰り返している 言語仕様がそうなっていることは認めるが 設計が悪い部分は無理して使わず良い部分だけ使えば良い話でもある
皆が皆そうしてくれないから自然に淘汰されていく訳だが
>>481 需要で言えばCOBOLでさえ無くなっていないからなぁ。
c++の完全置き替えはRustがようやっとスタート地点に立てたくらい。でもRustは初心者お断りだから無理なんじゃない?
個人的にはRustを参考にした初心者向けのサブセットC++か、Rustの複雑さをマイルドにしたスタックフレーム指向の新言語が出てくると思う。
>>487 誰が見てもC++よりRustの方が言語仕様も小さいしシンプルで洗練されていて学習しやすいよ
これは両方を使っている人なら必ず分かるから
>>487 は知らないものを妄想で語っている?
ちなみにRustはコンパイラによるアドバイスが非常に親切でプログラミング言語の中でもトップクラスな点でもC++との差異が大きいね
どうだろうなぁ。 C を学んでいる人が多かったというところから実務に使いながら少しづつ C++ に習熟していくという動線があったわけで、 C という前提が崩れたら Rust のほうが合理的に設計されていて楽かもしれないとは思う。 ただ、その一方で C++ が消えてなくなるほど劣勢になる気はしないんだよな。
c++とかcやってからじゃないと到底無理 ってよく聞くんですけど どういうことですかね?
class b:a{}; class a{}; このコードはコンパイルできませんが、aを前方宣言せずにコンパイルを通す方法ってありますかね?
1. class a; class b:a{}; class a{}; 2. class a{}; class b:a{};
>>491 個々のルールを頭に詰め込むだけってのはしんどい。
思想に沿うように個々のルールが制定されているので思想が分かればある程度はルールの想像がつく。
低レイヤで何が起こるかある程度は認識していると思想が把握しやすい。
C++ の駄目な部分を見た後に Rust を見ると「こういうのが真っ当な仕組みだよな!」という納得もしやすいし。
ただ、 C++ の「汚くていいんだ」というのもそれはそれで優しい世界なので私は好きだよ。
>>489 初心者からすればC++とRustの差なんて無いに等しい。コード1行書くのにいくつのルールを守る必要があるんだよ。
シンプルで洗練されている言語が初心者に良いというなら、RustよりFORTH(とその末裔)の方が初心者にふさわしいと思うわ。
>>495 FORTHはCと同等の速さを出せないし問題のすり替えはみっともない
RustはCと同等の速さを出しつつ現代的なプログラミングしやすい様々なパラダイムを洗練してシンプルにまとめている
FORTHを入れてC/C++/Rustの四者で比較してもRustがプログラミング効率も良いと同意できるだろ
夏厨って夏に湧いて出る厨房の事を指す言葉だったはずだけど その厨房も今じゃ中年おじさんなんだよな
>>497 Rustは初心者が学習しやすい言語ではないし問題のすり替えはみっともない
>>499 そうかな
C++(スマポ必須で所有権)よりはRustがシンプルではっきりと初心者向けだよ
自動解放で安全が前提でないと困るからその二つが比較対象で合っているよね
皆さんのオブジェクト指向に対する考え方 おください!
>>500 C++との比較なんてしていない。よく読め。
C++が駄目なのと同じくらいRustも初心者の学習コストはダメ。
C++はまだ部分的に汚く使う柔軟性を持つから、better c くらいのところから段階的に使う余地はある。しかしRustはいきなり複数の概念(所有権とか参照とかmoveとか)を使わないとプログラムが書けない絶壁の学習コストをしているから、「とりあえず使う」という選択肢が無い。初心者の選ぶ言語にはならんよ。
>>501 オブジェクト指向のオブジェクトは主体/客体のサブジェクト/オブジェクト。
プログラマー(主体)が操作・命令する対象(客体)をまとめて整理する考え方&手法がオブジェクト指向。
>>502 C++のスレで「C++と比較していない!」と言い出すそなたの頭のネジが飛んでるとしか
C++のスレでRustの話をする人の頭のネジは緩んではいないのか
他の言語との類似や相違など色んな話題が出てもええんちゃう 特にRustはC++後継言語の一つでもあるし
GAFAMがRustをC++の後継言語の1つとして位置付けてRust Foundationを共同で設立したりしてますもんね ただしGoogleは既存コードのメンテ用としてはCarbonもC++の後継言語の1つとして実験していますね Rustはシステム更新時や分離できる新たな部分に対してC++の後継言語となるのでしょう
>>504 C++関連としては
>>487 。
あとは「Rustは初心者向けじゃないからC++後継できるところまでは行かん」という主張に対する話。C++だって学習障壁から初心者取り込みできずにユーザー規模が縮小しつつあるのに、もっと絶壁のRustが普及するとは思えん。
C++後継としてはRust以外の初心者に配慮した言語が来るんじゃない?
スマポすなわち所有権を使ってるC++プログラマーならRustは簡単で楽勝 まともな案件ならばスマポ使っているし、急にではないけど、より安全なRustへ徐々に少しずつ移っていくんだと思うよ
>>506 それなら類似や相違など語り合うスレのほうがいいのでは?
無いなら立てれば良いし
C++の相談に来ているスレで今はRustだよなんて言われてもね
学習障壁でユーザー規模が縮小って なんかCOBOL臭えな アホフィルタを外すより待遇を改善すべきだろ マ板でやるべき内容だな
rustはアホでも書ける言語ではないよな 良いか悪いかはさておき
は? 「C++が使える」アホは俺でも知ってるが それがこの話と何か関係あるのか?
お前が知ってるかどうかなんか知るかよ 荒らしたいだけなら少し黙ってろ
都合が悪くなると荒らしたいだけとか全く C++相談室でRustを連呼するやつに言われたかねえな
相談者はチームで突然、Rustに変えようと言い出せば 解決につながるとでも言うのか そんな力のあるやつが相談に来るとでも?
手動メモリ管理のZigでは無理だよ 手動メモリ管理で複雑化したときにどうしても発生している穴を防ぐことがどのIT企業でも課題となっている
自動にしてもjavaみたいにメモリバカ食いしてるのも大概だけどな
shared_ptrやunique_ptrで特に問題ないと思うが? 手動メモリ管理ってパフォーマンスでも気にしてるの?
shared_ptrはほんとに良いものなのかちょっと疑問だわ
>>522 それはJavaがGC言語だからしょうがない
非GC言語でプログラマーによるコードに依存せず自動メモリ解放して欲しいならば現状Rustしかない
shared_ptrやunique_ptrで何か問題があるかな?
いらんわ まさかそんなくだらん話だったとは 買い被らせやがって
>>523 正確にはスタックフレームに積む or スマートポインタを使ってヒープに置く、だな。
shared ptrは関数呼び出し時の値渡しのインクリメントデクリメントコストが気になるところ。
スタックフレームに存在するかどうかで参照渡しか値渡しかを自動で切り替えると便利そうだけど、最適化で上手く処理してくれたっけ?
>>526 使い忘れと使い方ミスを常に完全にゼロにできるならばunique_ptrとshared_ptrでOK
しかし複雑化した時にミスを常にゼロにすることは不可能だと判明している
一方でC++からRustにすると以下のようなメリットが山のようにある
・Rustでは使い忘れや使い方ミスをするとコンパイラが必ず指摘してエラーとしてくれる
・Rustでは何も指定しない標準状態でC++のunique_ptrより高機能であるため記述がスッキリそして分かりやすい
・複数の参照があるとC++では参照カウントコストのかかるshared_ptrを使う必要があるがRustではそのコストを必要としない
などなど
この手の議論って「全てのプログラマがポインタを直に操作する必要に迫られている」という詭弁に基いていて辟易するんだよな
>>532 ある程度の大きなデータは抽象的な意味でcall by reference (pointer) により受け渡しすることになり実装的にはポインタを使わざるをえない気もする
>>529 Rustの変数をunique ptrと比較している時点でRustの利点を理解出来ていない。
Rustの変数に対応するのはあくまで自動変数で、unique ptr に対応するのはBox<T>。
Rustは「高速化と自動化のためにできるだけスタックフレームを活用する」という基本的な考え方があって、そのためにあの窮屈なルールで自動変数を高機能化している。
Rustの変数がデフォルトムーブだからといって、Rustの変数はunique ptr みたいなものとするのは理解の足りない粗忽者のやることだわ。
>>536 ある意味それも正しいが現実問題じゃないな
例えばi32を10個返す関数を作るとして
その型を[i32; 10]、Box<[i32; 10]>、Vec<i32>のそれぞれにした場合に生成コードはどうなりどれを選ぶべきか考えるとBoxの意義がなああ
結局Rustではもっと最適なものを選ぶからunique_ptr相当すら使うことがレアだよな
>>491 C++ちょっと分かったなーって気持ちになれるまでの遠い道のりを考えると、Cができるなんて入口にすら立ってない感じ。
だからC知ってたくらいではアドバンテージないよ。個人の感想です。
>>529 >・複数の参照があるとC++では参照カウントコストのかかるshared_ptrを使う必要があるが
>Rustではそのコストを必要としない
本当にコストは必要ないのかな?
本当に参照カウントしないのかな?
>>536 unique_ptrはmemory allocationとは全く関係ありません
unique_ptrなんて自動変数と変わらんじゃろ
>>539 Rustは借用(とライフタイム)があるから、
複数の参照が同時に必要となっても、
所有者は一人のまま何も変わらず、
複数の借用を普通に使うだけで済んでしまい、
付加コストの発生は無し。
一方でC++は、
複数の参照が同時に必要となる場合、
unique_ptrではもちろんダメなので、
shared_ptrを使わざるを得ず、
参照カウンタ増減という付加コストが発生。
>>540 デフォルトはヒープを想定しているだろ。
Rustの変数はデフォルトスタックを想定している。
そんなん設計でどうにでもなる ありきたりの道具使ってばっかいるからアタマが退化してんだろ
>shared_ptrを使わざるを得ず おまえがそう決め付けているだけで、ここら辺は設計でどうにでもなる
>>545 unique_ptrはコピーできないから複数の参照を用意できない
shared_ptrを使うことになる
同じクラスが重複して定義されたとき、 そのクラスに変数が定義されていてもコンパイルエラーにならないのはなぜですか? 関数が定義されている場合、インライン展開されないとコンパイルエラーになると思います 変数にはそのような指定が無いと思いますが、なぜエラーにならないのでしょうか?
言っている意味がちょっとわからないので最小のコードを提示してもらえるとありがたい
単純に、同じクラスを(同じ定義で)二回定義してもエラーにならんの 便利なようで不思議だよな
>>542 「複数の参照」が借用で済むようなものなら C++ でも T& でコスト要らなくね?
大抵インクルードガードで1回しか通らないようにしてたけど (クラス定義だけなら)インクルードガードなしで二重に読んでも通るってことなのか… それはしらんかった
>>550 それはダングリングポインタになりうるからダメ
C++には借用とライフタイムの概念がないため先に解放されてしまう事態を避けられない
以下のコードをヘッダに記述して複数のソースでインクルードすると、 関数fooは重複定義でコンパイルエラーになります inline指定にすると、コンパイルは通るようになります class myClass { public: void foo(); int i; }; void myClass::foo() { std::cout << "OK"; } このとき変数iは何故重複定義にならないのでしょうか? fooと同様に複数のソースで重複定義になる気がするのですが
>>542 コンパイル時に参照数が決まらない場合は参照カウントしてるやろ?
コンパイル時に決まるよう状況ならC++でもT&で十分
>>554 int i; はメンバ宣言に該当するがそれ自体は定義ではない。
クラス定義の中にメンバ宣言があるってのがようわからん理屈だがその時点では実体が作られない、
逆に言えばその型のオブジェクトを生成するときになって初めて実体が作られるので
この段階では重複として排除する必要がない。
>>553 参照を渡した先でどこかに参照を格納・保持して後で使う必要があるなら shared_ptr で
渡すのがいい状況になりそうだけど、その場合は Rust でも借用では済まないのでは?
>>556 ありがとうございます
グローバルスコープに定義するときは、
int i;
この記述で定義になるので、複数のソースでインクルードすると当然重複定義になります
クラス内では宣言のみになるとは思いませんでした
そういうものと覚えるしかなさそうですね
>>553 C++ にもライフタイムの概念はあるよ。
コンパイラが検査してくれないってだけ。
ダングリング参照を作ってはいけないというルールは C++ でも Rust でも同じ。
>>555 スマポを使っている限りは安全だと客観的にも保証されるけど
そこでT&を使ったら自己責任の世界に戻ってしまい意味なしとなってしまう
>>559 決定的な違い
Rustではダングリング参照するプログラムを絶対に作れない(コンパイラがエラーとする)
C++ではダングリング参照するプログラムがうっかり容易く生じてしまう(そしてコンパイラが通してしまう)
>>561 話変わってるだろ
検査してくれるかどうかじゃなくて
> ・複数の参照があるとC++では参照カウントコストのかかるshared_ptrを使う必要があるがRustではそのコストを必要としない
の話だったと思うが?
>>562 それはC++で安全を保証しようとすると
複数の参照を用いるならば常にshared_ptrの使用を必須とするしか安全を保証できないのに対して
Rustは複数の参照だけなら借用のみで安全を保証できるという話ではないか
ちなみにRustでは複数の参照ではなくもっとレアケースである複数の所有が生じた時に初めてコンパイラがRcを要求する
つまりRustでは参照と所有が明白に分離されているところが大きな違いとなる
>>563 安全の保証をコンパイラがやるのかプログラマーがやるのかの違いなんて議論してないよ
C++11以降のマナーでは、ダングリングは発生しない。 設計を見直すべきでは? 旧い規格、例えばDOMを実装する場合、設計を見直すことはできない。 ところで、DOMについて、C++によるGoogle Chromeの実装は素晴らしい洞察で問題を回避している。 後学のために読んでみるとよい。
如何にして安全なスパゲッティ・コードを書くかというのがRustのアプローチなら。 C++の方法論は、「安全なスパゲッティなど存在しない、素麺にしましょう」ということ。 旧式のスパゲッティ・コードを書きたい人にとってC++は役に立たない。
まぁ、c++でももっと積極的にスタックフレームに限定するアプローチは欲しいよね。 以前にインスタンスがスタックフレームに存在することを保証するスマート変数を作ろうとしたけど、インスタンス変数をどうしても制限できなくて挫折したことがある。 スマートポインタが必ずスタックにあるのなら、スマートポインタの参照渡しとかもっと活用できるのにね。
スタックかどうかなんてどうでもよくねえ? 機能の問題でしょ?
>>567 > 以前にインスタンスがスタックフレームに存在することを保証するスマート変数
それなんの意味があるんだ?
てかC++ならスタック上にインスタンス生成すればよくね?
大抵の環境でデフォルトのスタックサイズはそれほど大きくない。 数メガバイトというのは現代的な感覚では極端に小さいようにも見える。 でもまあだいたいこれで足りるし、足りるように書くのが普通なんじゃないの。
>>571 スタックオーバーフローしたら Linux/Unix は自動拡張しなかったっけ?
Windows はなぜか(オプションで可変出来るけどスレッド起動後は)固定なんだよね
>>573 そりゃ全部スタック上で済むならね...
>>574 割り当てが足りなくなれば拡張するが、その上限の設定がデフォルトでは 8MB になっている。
>>569 単にスタックフレームの入れ子のライフタイムを活用したいだけだな。
ポインタたくさん使う人っておじさんですよね? 実年齢か精神年齢かはともかく
>>577 ちょっと補足。
スマートポインタがスタックにあるのなら、shared ptr の参照とかポインタみたいなヤバイのもそこそこ安全に扱える。余計なインクリメントデクリメントも発生しなくて良くなるし。
なんでスタックである必要があるのかまったくわからん
>>578 おまえさん、いくつなんだ?
工房や厨房までがおじさんに見えるなんて
>>563 つまりコンパイル時に参照数が決まらない場合はRustも参照カウントする
>>529 >・複数の参照があるとC++では参照カウントコストのかかるshared_ptrを使う必要があるが
> Rustではそのコストを必要としない
従ってこれは間違っている
>>579 一見その通りだけど
関数で参照を返したい時に、その実体が呼び出し元(かそれ以前)のスタックフレーム上なのか、
それとも消え去る現在のスタック上なのか、安全を保証するために区別する情報が必要となる
そのためにはライフタイムをもっと明確化すればよく、参照が指す実体がスタック上でより深く(か同じ)ことを保証できればよい
すると更に大きな利点が生じる
実体がスタック上に無くてヒープ上に有っても、それを管理するスマポ相当がスタック上にあればライフタイムは同じとなるからだ
結局、スタック上かヒープ上かよりも、ライフタイムを明確化することが重要であると分かる
以上を言語仕様に組み込んだのがRust
>>583 c++も割と明確では
使いやすさはさておき
私もそう思う。 C++ でも明確で、解釈の余地はほぼない。 その上で知ってても人は間違うというところは問題で、チェックを自動化できるように整理したという Rust の功績は大きくはある。 ルール自体の差は C++ と Rust でそれほど大きくはない。
C++のライフタイムはプログラマーにとっては明確でもコンパイラにとっては明確でない そのためC++では参照の安全性をコンパイラが保証することができない そして複雑化した時に人間(プログラマー)はミスを無くすことが出来ない そのためC++で書かれた多くのソフトウェアで常に穴が発生し続けている
unique_ptrやshared_ptrを使えば良いだけではないかな?
>>587 C++ のスマートポインタはやっぱり後付け感はある。
Teratail とかの質問サイトを見てたら (コンパイル時にエラーに出来ない形で) 使い方を間違ってセグフォしてたりするのはちょくちょく有る。
コンパイラがガッツリと検査してくれる Rust はありがたいよ。
>>587 unique_ptrやshared_ptrの使い忘れや使い方ミスなどをしてもコンパイラはエラーとすることができないためC++は安全性を保証できない
他にもget()して得たポインタを関数などに渡した後にそのライフタイムを逸脱しないかなどの保証もできない
全ては人間頼みとなるため多数の穴が生じてきた
性能厨としては何でもスタックフレームに置いて集積度を高くしたいところ。レジスタの効率とかキャッシュヒット率とか変わるだろうし。 Rustのスタックへのこだわりはいいんだけど、無駄に抽象化しているから余計に複雑になっている感じを受ける。
C++のスマポは言語機能じゃないから書き方長くてだるいし 外部ライブラリは当然ナマポ使ってるから結局その辺でセグフォの危険を排除できないし オウムみたいにスマポでいいじゃん連呼してるやつは本当に使ったことあんのか?
>>592 使えば?と私は提案してるので「使い忘れ」は論外として
「使い方ミス」はどんなミスでしょうか?
ミスのしようがないほど単純だと思います
Rustのコンパイル時にチェックしようという設計は
もちろん良いと思いますよ
>>594 ええ
私は最近はメモリ管理で全く失敗ないですね
デバッガの出番がないです
スマポにハンドルを突っ込む方法はないですかねえ‥‥
>>596 君のような勘違い自信過剰な人がうっかりミスを起こして問題を引き起こしてきた
チェックを人間に依存している限りミスは必ず発生する
ソース記事
https://xtech.nikkei.com/atcl/nxt/column/18/00692/042700054/ グーグルによればAndroidに存在した深刻なセキュリティー脆弱性の70%近くがメモリー安全に関するバグに起因するという。
同様にマイクロソフトも、同社製品に存在したセキュリティー脆弱性の70%がメモリー安全に関するバグに起因すると述べている。
C/C++を使う限りセキュリティー脆弱性を根絶するのは不可能と
>>598 >
>>596 > 君のような勘違い自信過剰な人がうっかりミスを起こして問題を引き起こしてきた
私は最近はメモリ管理で全く失敗がないので私とは違うな
>>598 $ wget '
https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.19.1.tar.xz' $ tar xJf linux-5.19.1.tar.xz
$ find linux-5.19.1 -name *.rs | wc -l
0
2021年4月30日の記事だけどまだコミットがないようだが?
Rustのsuffixってひょっとしてrsじゃない?
>>600 それは貴方がアホだからミスに気付いていない可能性、使われないからバグが未発見なだけの可能性、単純なことしかしていないだけの可能性、…
複雑化すると、どんなにベテランでも、多数の人々がコードをチェックしていても、メモリ管理ミスが現実に起きている現実を受け入れましょ
>>602 俺が
>>600 で述べたのは俺のことのみだよ
>>604 ごめんごめん
>>598 がいちいち私を引き合いに出してきたので否定したまでだよ
>>598 の書き込みも冒頭の「君のような」を書かなければ
良いのに何でいちいち書くのかね?
どんな複雑なケースでも一度もミスをしたことがない!今後も絶対にミスをしない! と言ってる人を信頼できるわけがない
>>606 >一度もミスをしたことがない!今後も絶対にミスをしない!
そんなことは一言もいっとらんがなw
本当にunique_ptrやshared_ptrでミスするかい?
信じられないほど単純なクラスだと思うけど
>>592 の「使い方ミス」って何なの?
getで中身取り出して云々は割とあり得るんだろーけど
それはunique_ptrやshared_ptrの外の出来事だし
もちろんgetを使った時点でスマポ管轄外となり保証が全く無くなるが
スマポ自体における使い忘れや使い間違いなども色々とあるぜ
例えば
C++11スマートポインタで避けるべき過ち Top10
https://postd.cc/top-10-dumb-mistakes-avoid-c-11-smart-pointers/ >>609 有難う!読んでみたよ!過ちを列挙すると以下の通り
>過ちその1: uniqueptrで十分なところにsharedptrを使う
>過ちその2: shared_ptrで共有されたリソース/オブジェクトをスレッドセーフにしない
>過ちその3: 自動ポインタ(auto_ptr)を使う
>過ちその4: sharedptrの初期化にmakesharedを使わない
>過ちその5: オブジェクト(生ポインタ)を作成してすぐにshared_ptrに割り当てない
>過ちその6: shared_ptrで使用されている生ポインタを削除してしまう
>過ちその7: ポインタの配列にshared_ptrを使用する際にカスタムデリータを使用しない
>過ちその8: 共有ポインタを使用する時に循環参照を回避しない
>過ちその9: unique_ptr.release()で返された生ポインタを削除しない
>過ちその10: weak_ptr.lock()を呼び出す際に、有効か否かを確認しない
俺については4はmake_sharedを知らなかった時期にはやってたけど知ってからはないね
3はunique_ptrがstdに入って全部リプレースした
あとは過去にも犯さず使用しできてるよ
みんなはどうだい?
getを使ってしまったらthe endなわけだけど getの使用を皆無で頑張ってるん?
>>611 外部ライブラリの関数呼ぶのにget使うけど
意味するところを理解しているので
慎重になるから失敗した覚えはないなぁ
当たり前だけど自分の書く関数の引数に生ポインタを使うことはない
>>612 ところで複数の関数呼び出しそれぞれに参照を渡したい時はどうしてる?
生ポインタ使わないからshared_ptr?
>>613 その書いている「参照」ってのはC++の参照ではないですよね?
関数にT型のオブジェクトを引数として渡すとき
関数がシーケンシャルに実行されるなら原則としてT &で渡す
中身が無効値である可能性があるならunique_ptr <T> &で渡す
関数が並行に実行されるならshared_ptr <T>を渡す
T&渡した時にそれが他へ転用され保持されて生き残り続ける可能性を考慮しないの?
静的試験を絶対視するなーんにも分かっとらんやつが推すほどイメージが悪くなるな
>>616 だからポインタ使うの?
まあ寿命の長いオブジェクトを駆使しないほうがかっこいいのでは
>>617 動的チェックは不便だし重くて遅いよ
できる限り何でも静的にするのがベター
>>597 constructor destructor関数オブジェクトを用意すれば良かったんじゃなかったっけ?smart ptrの典型的な応用例だから、調べりゃすぐ出てくるよ。
>>617 俺も以前はそう思っていたんだけど
わずかな補助情報を人間が与えるだけで
Rustコンパイラが静的試験してくれて
人間にとって面倒かつ慎重さを必要とする作業から解放してくれるのを知って考えが変わった
例えて言うなら
動的型付け言語を使っていたところを
わずかな型情報を人間が与えるだけで
静的型付け言語のコンパイラが静的試験をしてくれるようになったのと似てる
昔とはソフトウェアの規模感が違う。 そしてプログラミングするのがプログラミングの専門化とは限らない領域が増えた。 (いわゆるエンドユーザー・コンピューティング) 職業的なプログラマにしてもプログラミングの専門化というよりは 別分野のそれぞれの専門化が道具としてのプログラムを作るというような場合も多い。 プログラミングのルールや作法を行きわたらせることは出来ないよ。 検査を強くするのは時代的な背景としても自然に思える。 動的な検査でも静的な検査でもいいが、 C/C++ は検査せずに未定義に突入するのがあまりにも簡単すぎる。
>>623 ナマポひとつロクに扱いきれないスキルと
動的チェックなんて恥ずかしげもなく言っちゃう
バカ用言語があんたにとって有難いのは分かったよ
ここはC++相談室
C++という土俵に立っている者の場だ
落ちこぼれて逃げ出したやつの遠吠えは
誰も聞きたがってない
どっか行け、邪魔なんだよ
自分のミスを道具のせいにするやつ そういえば法案のミスをワープロのせいにするバカ役人がいたな こういう手合いは一事が万事
>>616 が何を言いたいのか今もって分からない
悩む
一般用語の参照を使ってると思われるあたり
この人(
>>613 )はC++の参照を知らないレベルだと思うんだよね
C++に関してはほぼ知識がないまま
受け売りでRustが生ポインタを廃止?した利点を主張している
(私もRustのコードは書いたことがないんだけども)
この人は何がしたいんだろうか?
OSのAPIなりその他雑多なライブラリなりでポインタ要るからなあ・・・
動的型付け・・・あー、もしかして動的型宣言のことかな? だとすると具体的に何言語のことを言ってるんだろう? Bにはそんなもんないし・・・
昔構造体を値で渡したらポインタにしろっておっさんに怒られたっけ 速度を気にしないんだったらコピーでええのに糞めんどくさかったわ
>>630 動的型付けを知らないとは素人かね?
動的型宣言という言葉は存在しないぞ
>>633 それwikipediaソースだろpgr
で、あんたdynamic type declarationのことを言ってたの?
それとも他の何かか? Bにあったものか?
>>634 あまりにも無知すぎて話にならないな
wikipediaでも何でもいいから勉強して出直して来い
動的な型と動的型付けの区別は最低限つけろ
静的型付け言語の中には動的な型と呼ぶものもあるが
静的型付けと動的型付けは基本的に排反の関係だ
>>616 が何を言いたいのか今もって分からない
悩む
その一文がわからないようなレベルの奴がメモリ管理で全く失敗ないとか言ってんだもん みんな呆れてんだよ
>>637 本当に質問の意味が分からんから説明してよ
意味が分かったら返答するからさ
>>635 俺は動的な型と動的型宣言を混同していることを露呈するような失言はしてないぞ
していると言うなら具体的にどこなのかを示せ
誤魔化しても構わんがそれも返事と取るからな
>>628 にも書いたけどC++相談室で一般用語の「参照」は
C++の参照と混同するので普通は避けるんだよね
C++で書いた経験が皆無なんだなと俺は判断している
それで
>>616 のような意味を計りかねる質問をしてしまう
>>639 そこまで恥を再び晒したいなら示す
>>630 > 動的型付け・・・あー、もしかして動的型宣言のことかな?
まず動的型宣言という用語は存在しない
"動的型付け" はググると7万件あり
"動的型宣言" はググると3件である
一般的に動的な型の宣言の話と広く解釈したとしても
動的な型の宣言と動的型付けは異なり互いに包含関係などもない
動的な型の宣言は静的型付け言語においても持つものがある
そして動的型付けは静的型付けの逆であり相反する
>>637 説明が難しいなら簡単なコードでも良いよ
何を懸念しているのかそれで推察できると思うから
栄光在天 聖恩心から感謝申し上げます。 日ごろは激しい摂理の中、プログラム業ごくろうさまです。 さて、C++のコピーコンストラクタおよび代入演算子オーバーロードの質問でございますが、メンバ変数全てを関数定義内部で書き出すととてつもない量になってしまいます。 class Hoge { Hoge& Operator =(const Hoge&r); int hage=0; char sage=0; std::unique-ptr<Hagehage> pHagehage; etc… Etc… Eat… }; Hoge& Hoge::operator=(const Hoge&r) { hage=r.hage; sage=r.sage; pHagehage=std::make-unique<Hagehage>(r); Etc etc…… } メンバにユニークポインタがあるので書き出さないとダメな感じになっちゃうのですが……量がががが(>_<) これらにおいて、何か楽になるような裏技はありますか? それとも一つづつ足していかなければならないのでしょうか? もしかしたらコンパイラやIEDの部門で行うべき変な質問かなとも思いますが……何かやり方やティップがありましたら教えていただければ…… 相対的に有田退治にもなります!
>>643 メンバを
Hoge& Operator=(const Hoge&r)=default;
というように宣言すればデフォルトの定義が実装される。
全てのメンバに対して代入演算子を適用したのと同じことになる。
(もちろん全てのメンバを代入するという挙動で駄目な場合は自分で書くしかしょうがない。)
>>641 そのレスには動的な型についての言及がないな
誤魔化したいわけね、返事ありがとう
動的型宣言という言葉は存在しないと言いながら
動的型付けとは【意味が違う】とはどういうことだ?
存在しないものは比較できないはずだぞ
operator<=>でSFINAEだなpgr
>>643 そもそも代入演算子は特に指定しなくても定義されるはずだな。
(ただし基底とメンバの全てが代入可能であるとき。)
class foo {
public:
int x, y, z;
foo(int x, int y, int z) : x(x), y(y), z(z) {}
foo(void) : x(0), y(0), z(0) {}
};
int main(void) {
foo x(1, 2, 3), y;
y=x; // 代入できる
}
>>645 おかしな人みたいだからこれ以上は相手にするのやめとく
動的型付けを知らなくて間違えたことは仕方ないとしても
それを指摘された後の逆ギレはみっともないから治したほうがいいよ
>>644 >>647 規制されてしまいましたが643でございます。
メンバにユニークポインタがある場合は代入演算子とコピコンは削除された関数とされてしまい、コピーが実行できません(涙
ユニークポインタは明示的に複製されないとだめなのはわかるので、仕様には文句があるべくもないのですが……
例えばの話、データ型にint char等のメンバが100個あったとして、ユニークポインタのユーザー定義型が1個紛れ込むだけで、すべてのメンバを書き出しをしなければいけないのでしょうか?
みなさんはちゃんと書きだしているのですか?と疑問に思ったので・・・
まあユニークポインターを含むデータ型をコピーしない運用をなさっているのだと思うのですが、わたしは使ってしまいます(怒)
そこで、なにか裏技のような方法がないのかなとお聞きしてみた次第であります(`・ω・´)ゞ
>>651 コピーコンストラクターや代入演算子で
deep copyするunique_ptr作ればええがな?
>>652 メンバ変数 std::unique_ptr<My_Uniq> my_uniq; において
this->my_uniq=std::make_unique<My_Uniq>(*(right_arg.my_uniq.get()));
とコピーできるのはシンプルなのですが……
struct hoge
{
hoge& operator=(const hoge& r);
int a=0,b=0,c=0;
char d=0,e=0,f=0;
std::string g,h,q;
std::unique_ptr<MyHage> pMHage;
};
といった構造体において、
hoge& hoge::operator=(const hoge& r)
{
//メンバ全部かかなきゃいけない( ;∀;)
}
という感じになってしまうのが困るというか……もっと楽できないかなと思いまして(´;ω;`)
>>653 std::unique_ptrを使わない
カスタムのunique_ptr相当だよ
>>654 なるほど得心いたしました!
ユニークポインタをラップしたクラスにコピーコンストラクタを実装すればいいという……ってコト?
ですね?
ちょっと試してめます
643です 解決しました 皆様ご親切にありがとうござい甘いた ラップしてオペレーター実装すればいいだけだったとは…… こんなので悩んでるの私だけではないだろうか
>>656 携帯だったので書けなかったけどこんな感じで
template <typename T>
class deeep_copy_unique_ptr: private std::unique_ptr <T>
{
using Base_ = std::unique_ptr <T>;
public:
explicit deeep_copy_unique_ptr (T *p = nullptr): Base_ (p) {}
deeep_copy_unique_ptr (const deeep_copy_unique_ptr <T> &p): Base_ (std::make_unique <T> (*p)) {}
deeep_copy_unique_ptr &operator = (const deeep_copy_unique_ptr <T> &p) {Base_::operator = (std::make_unique <T> (*p)); return *this;}
using Base_::operator *;
};
>>621 それがそうでもないんですよ。だれか簡単なソースで示してくれませんか?
ハンドルごとにデストラクタがいろいろと変わるのが難しいと考えています。
ハンドルごとに異なるデストラクタを指定すればよいのでは? 何が難しいのかソースで示してくれませんか?
>>658 > ハンドルごとにデストラクタがいろいろと変わるのが難しいと考えています。
ハンドル毎にクラス作ればいい
と言うかハンドル毎にコンストラクタも色々変わるはずだがそっちはいいのか?
>>658 ポインタ以外のリソース一般を扱うための unique_resource クラスの提案は出ている。
一部の処理系では使えるようになっているし、ポータブルな実装があるので導入してみてもいいかもね。
このような提案が出ているのは逆に言えばスマートポインタではハンドルを上手く扱えないということでもある。
>>660 >ハンドル毎にクラス作ればいい
それはもうスマポじゃない‥‥
>>658 そのハンドルって何? ハンドルを具体的に指定せずにソースで示せとな?
#include <memory>
#include <cstdio>
#include <string>
using namespace std;
int main ()
{
using File_Ptr = unique_ptr <FILE, decltype (&fclose)> ;
const string path ("hoge.txt");
File_Ptr fp (fopen (path.c_str (), "w"), &fclose);
const string buf ("hage\n");
fwrite (buf.c_str (), 1, buf.size (), fp.get ());
return 0;
}
unique_ptr縛りですか? shared_ptrならコンストラクタの第二引数にDeleter関数を渡せるけど
私が言いたいことを
>>663 が言ってくれたみたい
こんな昔ながらのRAIIクラスでいいじゃん class FantasticHolder { FantasticHandle h = NULL_HANDLE; errno_t e; public: FHHolder(int flag, void* data, FOption option) { e = create_fantasy(&h, flag, data, option, false, NULL, Fantasy::DREAM); } close() { e = universal_fancy_destroyer(h, NULL, true, Fancy::FANTASTIC); h = NULL_HANDLE; } ~FHHolder() { close(); } const FantasticHandle& getHandle() const {return h;} erron_t getError const {return e;} };
>shared_ptrならコンストラクタの第二引数にDeleter ほんそれ
lzw書いたら、色々プリプロセス突っ込んでやったのにメルセンヌツイスタの前に敗北した。 2色ビットマップは1/5になったけど、ブロックソートがアホみたいに遅い・・・。Orz
サブルーチンsub、 subを呼ぶA、 subを呼ぶB、 があって、subをAとBからしか見えないスコープに置きたくなったんですが、そういうときはnamespaceを切るしかないですか?
>>671 sub, A, Bをひとつのファイルに入れてファイルスコープで区切るとかクラスにまとめてクラススコープで区切るとか
>>672 クラスに入れるとしたら毎回インスタンス作って呼ぶんですかね?
外から呼ぶためだけにstatic関数にするのもなーと思ってしまうのですが、そういうのはよくやられていることですかね?
Javaとかではstatic関数まとめクラスはよく見るけどC++ではあんまり見ない それこそnamespaceを使う
それはどうだろう。 namespace は内部を隠蔽しない。 キッチリと隠したいなら翻訳単位を分けるか、 翻訳単位内でも隠蔽したいならクラスに入れるかしかやりようがない。 やろうと思えば namespace で区切ってここにはアクセスしないことにするという 規約で運用するとかも出来るが、その程度で足りるなら そんなに分けなくてもよくない? って思うし。
subを公開ヘッダに書かずに非公開ヘッダに書くだけでよくね?もしくはヘッダを用意せずに各ソースコードからexternするとか。どっちも完全に隠蔽されるわけじゃないけど。 あとは全部同じソースコードに格納できるなら無名名前空間の中にsubを入れとくとか?
プライベートにズケズケ踏み込んで来るのは 友達としてちょっと...
おお!心の友よ! お前のものは俺のもの 俺のものは俺のもの
>>674 char_traits
numeric_limits
>>671 AとBがクラスなら共通のMix-inクラスをAとBでprivate(protected)継承するとか?
MessageBox()みたいな機能でボタンのテキスト変更できるファンクションありませんか メッセージが"ぬるぽ"なら[ガッ]のボタンを押したいじゃないですか! [ はい ]、[ いいえ ]だと"ぬるぽです。ガッする場合は[はい]を押してください"みたいに長々と説明しないといけないので(´・ω・`)
>>684 C++の標準ライブラリにGUIは用意されてないのよ
>>684 Vista以降ならTaskDialog
windowsのアプリの話 C++で作成するとランタイムが必要なんですか? Cならランタイムは不要ですか? windowsのアプリを作成するとしたらC++とCでどちらの方が良いでしょうか?
ランタイムライブラリはCでも必要 アプリ制作が目的ならC/C++はそもそも向いてないかもしれない 出来なくはないが、そのレベルの質問をするようだと今後苦労するかも
>>688 C/C++ のランタイムライブラリの一部は Windows の一部として入っているからその範囲内でならどちらでもあまり関係がない。
ランタイムライブラリの一部はVisual C++ 再頒布可能パッケージとして配布されているものもあるが Windows のバージョンによっては
最初から入ってるとかもあるのでそのあたりの事情は複雑。
バージョンの混乱を避けるならスタティックリンク版を使ったほうが楽だと思う。
Windows のアプリケーションを C で書くのはだいぶんしんどいと思う。
C++ なら楽というわけでもないけど各種フレームワークが C++ を前提にしていたりするので全体としては楽をしやすい可能性が高い。
ただ、言語仕様としては C++ のほうがだいぶん複雑ではあるので言語に対する習熟がどの程度かにもよる。
ランタイムは実行時に使われるライブラリ (およびその他の実行時サポート) で、 API はそれらを呼出すインターフェイスのこと。 ただ、そんなにしっかりした定義があるわけではなくて スタティックリンクするライブラリのインターフェイスを API と呼ぶかどうかなどは人によるかも? API の P はプロトコルの P なので独立性の高いモジュールの外部仕様なら 形態にかかわらず API と呼んでいいんじゃないかと個人的には思っているが。
ntdll.dll とか kernel32.dll は API って感じするけど それ以外は全部 Runtime で良いんじゃないかとも思う msvcrt を API かって言われたら絶対違う気がする
Application Programming Interface
APIは「境界面・接点」だから、インターフェイスの向こう側は対象外。 ライブラリは「書庫」なので、中身を含めてライブラリ。
ランタイムは、特定の開発手段(GCC, VSなど)に関係する実行環境に持ち込むもの APIは、特定の操作対象(OS、アプリなど)に関係する関数など
携帯電話をケータイと略してしまって何のことか判らなくなるのが日本人の本質
>>702 英語だと「mobile」だしそこは日本人に限らない
静的じゃなくて、かつ統合的な機能を提供しとるライブラリという感じ
いうて英語圏でも普通にRuntimeと表記されまくってるよ
CRTLよりCRTのが一般的だし。RTよりはRTLかもしれんが
>>703 したらわざわざ区別するような名称が付いたりしません
>>702 いや、プログラムから呼び出されるライブラリだけでなく実行時サポートのための機構全般を含めてランタイムという場合もある。
たとえば WebAssembly の仮想機械の実装である wasmtime も "A fast and secure runtime for WebAssembly" と説明されている。
https://wasmtime.dev/ 明確な用例を見つけられないんだけど .NET とかでも同じようなニュアンスだったはず……。
おまえらは用語の定義とかの話になると生き生きしはじめるな
WebAPI はどうでもいいとして Win32API 以前は API ってあんまり聴かんかった気がする もし時代が時代なら C Runtime は Console API とか System Call API とか名付けられていたんじゃまいか
Linux界隈でもランタイムって用語は あんまり馴染みない気がする
ランタイム (実行時) という語をあてはめる以上は静的ではないというニュアンスが感じられるし、 ダイナミックリンクされるもの全般をふんわりとそう呼び始めたとかではないかなぁ。 あくまでも想像の域を出ないけど。 >710 それはどうだろう。 C ランタイムはコンソールの操作だけを司るわけではないし、ほとんどの関数はシステムコールしない。 あくまでも C という言語の事情に強く結びついているのでランタイムとは呼ばれなかったとしても C ナントカという名前にはなったんじゃないかな。
DOSの頃はINT21hのシステムコールだしな。 描画はVRAM直だし。 APIと言うより割り込みだな。
APIという言葉からは、実装を絶対に見せたくないという強い意志のようなものを感じる
>>716 DOS の用語ではファンクションコールじゃなかったっけ……
と思って資料を読み返したらなんだかあまり統一されてない感じだった。
ファンクションリクエストという用語を使っている場合もある。
当時の用語の混乱は置いといて、現代的にには
機械語レベルでの値の受け渡しやメモリの配置は ABI で決めるべきことで
API はその上に構築される高レイヤな概念と解される場合が多いと思う。
ソフトウェア割込みを使うという規約は ABI に属して、
どのような値を渡してどんな効果があるかは API に属すと考えるべきじゃないかな。
メインフレームではSVC DIAGNOSEを使う馬合もあるけど
こんなのがあったんだけど
https://qiita.com/purigen/items/d68b146f341c41d260fc c = c = testString.find_first_of(" ")
これってなんで2回も代入してりゅの???わからにゃいよ
Win32の頃はint2ehのだしな 描画はシステムメモリに書いてbitbltだし APIと言うより割り込み棚
g++で以下の警告のようなメッセージ(`note')が出るのですが これは何を意味しているのでしょうか? コンパイラはaarch64-linux-gnu-g++-10で オプション-std=c++14に変えるとメッセージは出ません またx86_64-linux-gnu-g++-10でコンパイルすると -std=c++17でも-std=c++14でもメッセージは出ません 恐らくC++の規格の問題だと思いますのでこちらに書かせて頂きます $ cat test.cpp #include <cmath> #include <utility> using namespace std; pair <double, double> hoge (double p_x, double p_y) { return make_pair (p_x, p_y); } int main () {return 0;} $ g++ -std=c++17 test.cpp test.cpp: In function ‘std::pair<double, double> hoge(double, double)’: test.cpp:6:29: note: parameter passing for argument of type ‘std::pair<double, double>’ when C++17 is enabled changed to match C++14 in GCC 10.1 6 | hoge (double p_x, double p_y) | ^
俺んとこでは -std=c++98 でも何も言ってこない バージョンは g++ (Rev5, Built by MSYS2 project) 10.3.0 Microsoft(R) C/C++ Optimizing Compiler Version 19.33.31629 for x64 で /W4 にしても何も言ってこない
>>726 言語仕様上は問題ないけど、どうやら特定の環境で起こる GCC のバグを修正した
ために ABI の辻褄が合わないかもしれないというような事情っぽい。
>>727-729 有難うございます
難しすぎて書いてあることが良く分からんのですが
ABIなのでビルドし直せば問題ないと理解しました
みなさん凄い調査能力だな
>>730 いや、エラーメッセージでググったら stackoverflow で背景の説明をしてるのが見つかったぞ。
OSの板で聞くべきかもしらんが、終了シグナル受け取ったらメモリの中身を書き出して中断し、再びコマンドが叩かれたらメモリの中身を読み込んで途中から再開するみたいな仕組みを一番簡単にやる方法ってどんなですかね? チェックポイント・リスタートっていうんでしょうか
>>733 Linux とか BSD で昔はメモリをダンプするシステムコールがあったはずだが廃止されたんじゃなかったっけ。
Emacs でそのシステムコールを使ってたから色々とゴタゴタしたような記憶がある。
(そのシステムコールの名前が思い出せない……。 すまぬ。)
再開に必要な情報を適当にシリアライズして書き出すしかしょうがないんじゃないの。
おはこんばんわ 何度もお世話になっておりますが、今回も皆様のお知恵をお借りしたく書き込みをしております。 初歩的な質問かもしれませんが質問させてください! 私の質問は、動的な任意型を戻り値とする関数を作ることは可能でしょうか??という事です。 したい事は、 template <typename T> T ret(int arg) { If(arg==0)return static_cast<hoge>(arg); else if(arg==1)return static_cast<hage>(arg); } でホゲ型とホラン千秋型を引数によって変化させて返却したいのです……が、 私が見ても無理そうな感じなのです。ニパー そもそもテンプレートってコンパイル時点で推察できないと無理ですよね? この悩みに何か方法や別解があったりしたら教えていただきたく、スレ汚しを失礼しております。 感謝は先に申し上げておきます。 ありがとうございます!
>>737 一般的には型システムの健全性と安全性のために
そのような用途では代数的データ型(タグ付き共用体)を用いる
C++ではstd::variantであるがパターンマッチングなどの言語サポートがないため若干扱いにくい
>>737 実行時の多相は抽象クラスを使うのが基本ということになってる。
その場合で言えば hoge と hage が共通のインターフェイスを持つ (抽象クラスを継承する) ようにクラス設計するのが普通。
まずは抽象クラスを学んでみて。
最初からクラス設計に関与することが出来ない場合 (既存のライブラリなので手を加えられないなど)
に動的に切り替える必要があるなら std::variant や std::any が使えるのだけれど……
使う箇所で元の型にキャストしなおしたり、 std::visit を経由したりで煩雑になりがち。
>>737 argがコンパイル時点で決定しているのならやりようはあるが
実行時まで決まらないのならみなさんの言う通り
retをどう使うのか呼び出し側のコードを書いてみてよ
>>740 入ったのは C++17 だし、あまり積極的には使わない種類のものだから目立たないよな……
any使えばクソコードは書けるがw #include <iostream> #include <any> using namespace std; struct hoge { int value_; hoge (int arg): value_ (arg) {} std::ostream &output (std::ostream &os) {return os << value_;} }; struct hage { int value_; hage (int arg): value_ (arg) {} std::ostream &output (std::ostream &os) {return os << value_;} }; std::any ret(int arg) { if(arg==0)return hoge (arg); else if(arg==1)return hage (arg); return std::any (); } int main () { try { any_cast <hoge> (ret (0)).output (cout) << endl; any_cast <hage> (ret (1)).output (cout) << endl; any_cast <hoge> (ret (1)).output (cout) << endl; // An exception will be thrown. } catch (const std::bad_any_cast &) { cerr << "std::bad_any_cast\n"; return -1; } return 0; }
argがコンパイル時に決まってるなら例えば以下の通りにディスパッチ Loki::Int2Typeって今はC++に入ってるっけ? #include <iostream> using namespace std; namespace Loki { template <int v> struct Int2Type { enum { value = v }; }; } struct hoge { int value_; hoge (int arg): value_ (arg) {} std::ostream &output (std::ostream &os) {return os << value_;} }; struct hage { int value_; hage (int arg): value_ (arg) {} std::ostream &output (std::ostream &os) {return os << value_;} }; hoge ret(Loki::Int2Type <0> p){return hoge (Loki::Int2Type <0>::value);} hage ret(Loki::Int2Type <1> p){return hage (Loki::Int2Type <1>::value);} int main () { ret (Loki::Int2Type <0> ()).output (cout) << endl; ret (Loki::Int2Type <1> ()).output (cout) << endl; return 0; }
>>738 >>739 返信ありがとうございます。
variantで返すかUnionのようなもので返すか、という事ですね。
Unionの存在を初めて知ったので、できれば使いたいと思います。
そういう用途でタグ無しunionは危険で不便な昔の遺物 どの言語でも安全で便利なタグ付きunionを用いる C++はパターンマッチングが弱いのでそこを改善すればさらに便利になるはずだ
anonymous union というとなにかこう、不穏なひびきがあるな 集団で徒党をくんでハッキングする的な
そもそも文脈なしのunionって労働組合だからもともと不穏な響きの単語
Visual Studio Community おそろしあ
ちょっとわからなくなってきたため良ければ教えてください。 他言語を使用していて強く感じることですが、.hと.cppを行ったり来たりする開発スタイルがかなり面倒に感じます。 ヘッダに実装を書いても普通にビルド出来てしまうため個人的な開発はヘッダオンリで済ませています。 何番煎じの話かもしれませんが、分割するしないでのメリット・デメリットを教えてください。
再コンパイルコストとインターフェイスと実装の分離 hに全部書いてしまうと、それの変更があった場合にincludeするすべてのファイルで再コンパイルが走り、時間がかかるようになる hに全部書くため、変更の機会も当然多くなり、頻繁にビルド待ちの状態になるのは避けたい インターフェイスと実装を分離しておくことは、保守や共有の最、理解を早くするという点で有用 どっちの話も大規模になると効いてくる話なので、小規模開発なら全部.hに書くスタイルでも構わないとは思う
>>757 C の延長線上でなんとかしてきた C++ の言語仕様があんまり良くないんだよ……。
実装とインターフェイスを分けるのはカプセル化の観点からも好ましいのだけれど
C++ ではテンプレートを処理する都合上でこの分離が破綻しているので
そこらへんはまあ運用の工夫で……みたいな微妙な機微がある。
どうにもならんのがわかってるから新しい C++ ではようやくモジュールが導入された。
FILE * は使っても struct FILE の中身なんて知らなくて良いからな 使うだけなら void * で充分
c#みたいにヘッダ無いのが良いことだとは思えんのだよなあ
C#だけでなく今世紀のプログラミング言語は全てヘッダファイルなんて無いんじゃない? 不要なものなんだと思うよ
.hppって拡張子でヘッダに処理を書いてるのを見たことある
>>763 .hpp は C++ のヘッダとしてはありふれた拡張子。 定義を書くかどうかとは関係なく使われるよ。
昔は .hxx とか .h++ とかもあったし、テンプレートが含まれるヘッダには .tcc と付ける習慣が一部にはあった。
大文字で .H とか付けてるのも有ったけどファイルシステムによっては大文字と小文字が区別されないから早い内に廃れたと思う。
C と共用できるように書かれたヘッダを除いては .h という拡張子は避けたほうが運用しやすいと思うんだが、
そこらへんの考え方も慣例が確立していなくてなんだかグダグダなんだよなぁ。
>>763 template主体ならhppにガッツリ書いてたけど、ちな、どこに書くの?
ヘッダはテンプレートでごちゃごちゃしてなければどんな構造してるのかパッと見で分かりやすい
ヘッダに実装書く必要がある場合は 俺はインターフェース用ヘッダと実装用ヘッダに分けてるな ヘッダには本来インターフェースのみが簡潔に書かれているのが望ましいと思う
他のプログラミング言語はヘッダファイルが無くても困っていないから ヘッダファイルは大昔当時のCコンパイラがサボるために用意しただけの本来は要らない子なんじゃ?
ソース公開出来ないようなハード実装ライブラリを隠蔽して提供するためにはヘッダは必須項目
>>769 ハード実装をヘッダで表現することはできません
ソフト実装のみです
>>768 必須じゃないけど便利だよ
使いたいけど実装なんか見たくないときは
プロトタイプだけヘッダに書かれてれば
それだけ見てれば良い
>>771 時代遅れすぎだろw
今はそんなヘッダファイルを見なくても
ヘッダファイルが存在しなくても
ソースファイルから自動抽出されたもっと見やすい表示や生成ドキュメントを見る
だからC/C++以外はヘッダファイルなんて存在しない
>>772 >ソースファイルから自動抽出されたもっと見やすい表示や生成ドキュメントを見る
それはヘッダがないから仕方なくなのではないかな?
C++でも自動抽出ツールされたドキュメントを見ても良いのだよ
>>773 つまりヘッダファイルの必要性はない、との結論になりますな
実装とインターフェイスを分離するという根本思想自体はよかったと思う。 それを実現するためにプリプロセッサで単純にヘッダをはめ込むというのは雑すぎるやり方だとも思う。
他の言語はヘッダ無くても何も困っていないから 本質的にはヘッダは不要物なのだと思われる
マルチパスコンパイルするオプションがコンパイラにあればいいのにね
>>777 古い bcc には、確かヘッダを自動抽出するオプションがあった気がする
仕組みが簡潔でドライなシステムを好む人もいるし もはや把握しきれないカオスなシステムに帰依する人もいる 俺は前者だし、これからもそうありたい
カオスは崩壊へと繋がる ATiのCatalystのようにな
実装とインターフェイスの分離の点でC++が甘いのは classのメンバー変数がヘッダに書くところ 俺はデフォルトでpimplにしてるけど
>>780 最近の言語はどれもその簡潔な方式だよ
ヘッダファイルとソースファイルは二重管理だからソースファイルに統一
さらにソース付随コメントとドキュメントファイルも統合してソースファイルにのみ記述
シンプルになってる
自動生成みたいなことしても、特に見通しがよくなっとらんと思うんだよね ヘッダファイルじゃなくてもいいけど、どこかでユーザにインタフェース提示を強制する必要はある気がする
>>784 多くの言語は関数定義かそのままインターフェース宣言を兼ねていて一元化されてるよね
バラバラに用意することこそ不自然なのよ
いや俺はインターフェースは簡潔にヘッダーにまとまってる方が良い 管理が二重になっている云々は同意せんでもないが 同一性はコンパイラがチェックしてくれるので全く問題なし ドキュメントの自動生成ってリアルタイムに更新してくれるんかいな? Doxygenみたいなのを想像してるんだが?
C++に慣れすぎて実装とインターフェースが混在してるソース見ると 俺は読みたくなくなるんだが?
>>787 めちゃめちゃわかりすぎる
関数なりクラスなりの定義部分だけ切りだして別ドキュメントにまとめてくれや(’A’)
っていう気分にいなる
>>785 いや兼ねていてというか、ない
だからサポートするソフトが何らかの方法で提示してるんだけど、必ずしも見やすくなってないのは問題
>>768 ヘッダを分けるのは最初は処理系の実装上の都合だったのは事実だと思う。
素朴なオブジェクトファイルは名前とアドレスの組でしか管理していない。
具体的な型をやりとりする仕組みは必要で、それがヘッダファイル。
リンカなどのツールチェインが充実していないのを
コンパイラとプリプロセッサがカバーする形なのでツールチェイン全体が上手く連携できるなら
ヘッダという仕組みは無くても良い。
それはそれとして処理に必要かどうかと言語の表現はまた別問題だ。
原理的に必要かどうかだけで言うならバイナリエディタだけあればプログラムは作れることになってしまうよ。
言語は機械に処理させる以上に人が読み書きする。
もちろんどんな言語が分かり易いかは人によるだろうけども
C++ に満足している C++ ユーザは実装とインターフェイス分離することを利点だと考えている場合は確実に多いよ。
私もそうだし。
単にヘッダファイルに慣れていて愛着があるだけです 冷静に考えれば分かります 他の言語はヘッダファイルがなくても機能しています つまりヘッダファイルは不要なものです 他の言語はヘッダファイル方式を採用しませんでした つまりヘッダファイルを採用するに値するアドバンテージはありません
今は必要に応じてIDLを使うようになっているだけじゃない?Protobufぐらいしか知らないけど。
>>791 C++もヘッダに実装書けば似たようなソースになるけど
読み難いんだってば
c#のプロジェクト、実装してから設計起こした様なグダグダなのばっかになってるよね pythonだとそうはならん気がするけど
obj や lib だけを提供する場合は、ヘッダは絶対に必要かと 他の言語ではどうしていますか?
ヘッダは無くてもいいがある方が便利なときがある 使い回すマクロの定数とか定義とかヘッダに書くのが一般だし 誰かが書いてたけどヘッダファイルに関数の説明とか書くスタイルなら そこだけ見れば済むようになるし 無くても困らないけど結局は include xxx.c なんてソースコードを見ることなると思う
>>795 javaは起動するときに.classファイルの中にある関数名を見てるのが
通常じゃないのかな
ラムダ式でコピーキャプチャした変数ってなんでデフォルトで immutable なの? あとそれに関連してるかもしれないけど、const int a があったとして、a をコピーキャプチャして mutable をつけたラムダ式の中で a を変更しようとすると許されないんだけど、これもなんで?
ミスか? 俺はGJと思ったぞ constの逆は欲しかった 明示的に書き込み許可すんの
ヘッダなんて特別なものはなくて includeディレクティブがあるだけ
C++11以前なのでoverride演算子がないソースコードなのですが、 派生クラスでオーバーライドされている関数を簡単に見つける方法って ありますか? virtual関数を1つずつgrepするしかないですかね。
>>803 何の前提も無ければ自分がソース持ってないところでオーバーライドされてる可能性もあるので、
いろいろ前提を絞らないと無理かと。
override (「演算子」じゃなくて「キーワード」)があったとしても、付け忘れてる可能性もあるし。
>>804 失礼、修飾子でした。
やっぱそうですよね。
継承が3階層あって、その中間階層クラスのメンバ関数なので調べにくいのですが、
地道に1つずつチェックしようと思います。
ヘッダに実装が書かれててもエディタでショートカット1個押して折りたたむだけでインターフェースすぐわかるくね?
まっとうならバイナリなりだけ開発環境でインポートすれば、 綺麗にインターフェイスが見える。
共有オブジェクト (ダイナミックリンクライブラリ) の段階にまでなってしまうと型は別のところから与える必要があって、 基本的にはビルドの時に型情報を表すなんらかのファイルも生成できるけど、めんどいのは言語をまたぐときなんよね。 Windows API はいろんな言語から使えるような (バインディングの生成元に出来るような) メタデータを提供するという形で 対処しているのでこのへんは Windows API に限らず使いやすいように規格化や環境整備が進むことを期待している。
今はLinuxでgcc+vimを使っています。 どういう環境なら見えますか?
>>809 近頃は vim も LSP に対応してるはずだから clangd と合わせて使えばいいんでないの。
わいは vim についてはよう知らんけど VSCode では出来ているから原理的には出来るはず。
>>810 ,811
似たようなツールでdoxygenを使ったら簡単に見つけれるようになりました~
ありがとうございます!
>>795 obj と lib と h (hpp) だけじゃ不十分
バージョン管理も必要
これ重要
サイズが可変な自作クラスXのvectorを持ちたいとします。 このとき、Xの実体をいくつかvectorに入れて不用意に各要素のサイズを変更すると、メモリの割り当てがおかしくなりますよね? 実体ではなくポインタを持つ以外のワークアラウンドはありますか。
>>817 メモリの割り当てがおかしくなると思う事例をコードで説明して。
>>817 「サイズが可変なクラス」の簡単な具体例を教えてくれないかしらん?
>>817 出来ます
Xの参照(ポインタ等)のベクターを持ちます
Xのサイズが可変でバラバラでも構いません
もしXのサイズに上限値があるならば
別の方法としてその上限値サイズのベクターを用意する方法もあります
>>819 boost::multi_array の resize
>>820 ?
それは
>>817 の最終行の冒頭と何が違いますか
sizeof の結果は常に定数なんだよね……。
https://timsong-cpp.github.io/cppwp/n3337/expr.sizeof#6 (C では VLA まわりで定数にならない場合もあってその挙動を拡張として取り入れている C++ 処理系もある。)
そういう意味ではサイズが可変なクラスは存在しない。
>>821 boost::multi_array もそれ自体の大きさは一定。
内部的にはポインタで保持してる。
やっぱり817が思ってる「おかしくなりますよね?」の最小コード提示してもらわないと 実はそれおかしくならないって結論になりそうなんだが?
つまりおかしくなる理由が分からない人が相談に答えようとしているわけだな。
>>819 ,821,823の流れで解決してると思うのだが
>>817 が返答も何もしないので
>>824 のようなのが出てくる
「サイズ(sizeof)が可変なクラス」なんて存在しないから817が何かを勘違いしてるのは確かだが 何をどう勘違いしてるのか分からんからお前さんの信念でコード書いてみなって話だろ 別におかしくない
>>821 で
>>817 の考えていることは明らか
>>823 以上は蛇足だよ
>827 単にお前の読解力の話でしかなかったのか。 「サイズが可変な」はvectorに掛かってると考えるだろうふつう。理由は > 「サイズ(sizeof)が可変なクラス」なんて存在しないから と自分で指摘してるとおり。
「サイズが可変な」はクラスに掛かってると考えるだろうふつう。vectorは当然サイズ可変なんだから
sizeof(std::vector<T>)なんて気にせんだろふつー
まあクラスのサイズが変わるようなイメージだったよね
コード見せろ、この日本語が分からない奴に このスレは無理
質問者です 皆さんのおかげで解決しました ありがとうございます
817の類似
https://ideone.com/81vcNn e1, e2 と list の要素は別物だけど (2) の操作で list も同じく反映するようにするには
list を vector<X*> として ポインタ渡す他に何か手段あるのかな
std::vectorもboost::multi_arrayも要素数の変更ができるけど、その可変可能個数要素を格納する領域はクラスのインスタンスとは別のヒープ領域に確保されるようになっていて、クラスのインスタンにはそのヒープ領域へのポインタが格納される したがって要素数を変更してもクラスのインスタンのサイズは変わらない だよね?
>>837 なぜ上で書かれてるのと同じことを書きたくなったの?
>>836 listに手を入れるとか手段はあるだろうけどそもそも
> list を vector<X*> として ポインタ渡す
で何が問題なのかを書いた方が良いかと
>>840 自分で質問しといてなんだけど、たいした問題点でもなかったりするんだよな…
vector<X*> list; だと要素をアクセスする際に記述が煩雑になるところ
list[i]->size(); ←おけ
list[i]->push_back(hoge); ←おけ
(*list[i])[j]; ←きもい
実体のポインタを list に詰まず new したものを詰んだ場合 お漏らしやタングリングポインタになるかもしれんってのもあるかな これだと問題点が前提とは別のところになりそうではある
>>841 ラッパー書きゃよろしいがな
template <typename T>
class Vector: private vector<T>
{
using Base_ = vector<T>;
public:
using Base_::push_back;
using Base_::size;
const typename remove_pointer <T>::type &operator [] (size_t i) const {return *Base_::operator[] (i);}
typename remove_pointer <T>::type &operator [] (size_t i) {return *Base_::operator[] (i);}
};
Vector<X*> list;
list[i]->size();
list[i]->push_back(hoge);
list[i][j];
>>841 > (*list[i])[j]; ←きもい
list[i]->operator [](j) ← う~ん、もっときもいかw
>>842 まあ今時生ポインタは使わんわな
shared_ptr とかを入れれば多少安全かと
>>834 どう解決したのかコメントを求む
まだ憶測他で引っ張ってるし
>>845 それはただのポインタトリックであってsizeof(info_t)が可変になる訳じゃない
というかそのページでもsizeofのこと説明してんじゃん
相変わらずの無能っすね
>>847 元の質問
>>817 はサイズが可変としか言っていない
つまりsizeofが固定であり可変でないという話こそどうでもよい話
本件は
>>845 氏の指摘する可変なサイズの構造体を作れる話が適切に該当していると思う
>>819 と聞いて本人は
>>821 と答えてるのに
何でそんな解釈を無理やりしてるのかサッパリ分からん
>>841 思い出したけど boost::ptr_vector なるものもある
クラスメンバBの初期化が終わる前に、メンバAのコンストラクタにBのアドレスを渡すのって合法ですか?
マルチアレーで思い出したけど、多次元配列クラスのSTL入ってどうなった? boostとか自作クラスで対応せよってのは暴論だぜ 前者はパフォーマンス微妙だし管理されてない、後者はそれ言うなら何でもそうじゃん
>>851 アドレス渡すだけなら合法
中身触ったら違法
>>852 template <typename T, size_t N0, size_t N1>
using multi_array = array <array <T, N0>, N1>;
>>852 std::mdarrayのことなら揉めに揉めて伸びに伸びて今は一応C++26の予定
でもまだグチグチ揉めまくって収拾がつかなそうだからもう無理じゃないかな
代わりにstd::mdspanっていう配列に被せるガワが入りそう
各次元の長さが可変で、全添字の走査が速くて、メモリの並びがFortran流かC流か選べるだけで良いのに何を揉める必要があるのか
その程度なら自前で直ぐに作っちまいそうだが 標準に入ってることが意味あるんだろうな
そりゃそうじゃね 「std::vectorよりも自作の配列クラスの方が優れてる」という主張が本当だったことがない
>>849 無能君はひっこんでなさい
>>848 ですよね!
SIMD まで自分ではやりたくないのでnumpyを呼ぶのほうが早い
>>865 実際自分にとってはそんな感じですね。C++でpython とcudaとかopenmpを糊付けしている感覚があります
set, mapというデータ構造があります。 mapはキーと値のペアをハッシュテーブルや2分探索木に格納しているのでしょうか?
平衡二分探索木です ハッシュテーブル版はunordered_*です
ハッシュテーブルの方が大抵の場面で速いと思ってええんか?
>>869 データの性質や使い方によるのでなんとも言いにくいが基本的にはハッシュテーブルが速いことは多い。
差し替えるのは簡単だろうし、やりたいことをとりあえずやってみて測定すればいいんでね?
>>869 実際にベンチマーク取らないとわからない。
基本的には種類が少ない場合は計算の軽い探索木が、多い場合は定数オーダーのハッシュが有利。
>>871 ハッシュテーブルのサイズ、という地雷的制約は好まないのですけれどもね
std::map::operator[] は O(long(N)) のオーダーなんだが、 std::unorderd_map::operator[] のオーダーは平均で O(1) 、最悪で O(N) ということになってんよね。 意図的に最悪を引き当てる、つまり攻撃に晒されるような状況では unorderd_map のほうが不利になる可能性もある。
C++の例外処理は、class SomeClass {}; と中身の無いクラスであっても、 throw SomeClass{}; をcatch(SomeClass) {・・・} で受け取ることが出来るらあしいけど、 どういう仕組みでcatchは、例外の種類を識別してる? "SomeClass"のようなclass名の文字列のポインタでも一緒に渡している のだろうか? typeid(x)は、RTTI(実行時型情報)が必要で、仮想関数が定義されて無いクラス に対しては上手く働かないのではなかったっけ?
まず基本を禿の本でも規格票でも読んで C++例外処理ってそもそも何ってとこをわかってから 出直したら? そんな有様じゃマトモなレス付かないよ
>>874 typeid と同等の情報で照合すれば可能ではあるんだから、何を不思議に思うことがあるのか。
「上手く働かないのでは」なんて言うぐらいならコード書いて確かめればいいだろうし。
>>874 例外を送出してスタックの巻き戻しをするのは例外を送出する側 (受け取る側ではなく) なんだよ。
つまり送出される例外オブジェクトの型はわかっている。
むしろどこまで巻き戻せばよいか (送出されるオブジェクトの型に対応する catch はどこにあるか) の情報が動的なものだ。
メンバ変数をまったく使っていないメンバ関数を見つける方法ってなんかある? CppCheckとかでできるんだっけ
>>876 typeidは仮想関数を持っているクラスにしか働かないと思っていたが、
働くのか。
typeid(x)の返すオブジェクトは完全にtype_info型なのか、 それとも、type_infoを継承したクラスなのか、どっち?
それこそtypeidに聞いてみりゃいい cout << typeid(typeid(some_one)).name();
T x; T y; に対して x=move(y); //(1) とした場合、時系列的に 1. move代入演算子 T::operator=(T &&a);がyの中身をxに入れる。但しこれは、2とも 関連しているがswap(x,y)とされることもある。 swap(x,y)を使わない場合には、xにyの中身を入れる前に元々の xの中身が削除される。 2. swapを使って無い場合には、続いてmove代入演算子 T::operator=(T &&a);が y のポインタメンバなどに null 値を書き込む。 3. (1)の式の最後で、右辺のオブジェクト y に対してデストラクタが呼び出される。 4. デストラクタは、y ポインタメンバが null だと何も行なわない。 yの中身がxに交換されていた場合は、もともとxの中身だったものを削除する。 というような流れになるという理解で合ってる?
>>885 特に確認したいのは、
>3. (1)の式の最後で、右辺のオブジェクト y に対してデストラクタが呼び出される。
の部分。
stroustrup氏によれば、yに対するデストラクタが必ず呼び出される、ということ
らしいが、それは常に正しいのかな?
>>886 > stroustrup氏によれば、yに対するデストラクタが必ず呼び出される、ということ
> らしいが、それは常に正しいのかな?
そういう型を作ることはできるけど、そんな動作をしたらスコープアウトで走るデストラクタを
止めないといけなくなって非常に使いづらくなる。正しくなさそう。
あなたが何か読み間違えてるものと思われる。
>>887 move代入の右辺のオブジェクトは、事後にデストラクタが呼び出される、
と書いてあったと思うが。
xの元の中身も適切に破棄されますよっていう話を歪んだ理解してそう
>>888 [訂正]
正しくは、
・move代入演算子 T::operator=(T &&a) 自体はデストラクタを呼び出さない。
・x=move(y) と書いたとき、コンパイラが 右辺の y に対してデストラクタを呼び出す。
2つのパターンが有る。パターン1:swapを使う。パターン2:swapを使わない。
いずれにせよ、コンパイラによって y.~T() が呼び出される。
擬似等価コード:
x.operator=(rvalue(y));
y.~T();
パターン1:
T &T::operator=(T &&a) {swap(*this,a); return *this:}
パターン2:
T &T::operator=(T &&a) {thisの中身を削除; aの中身をthisにコピー; aにnull値を書き込む; return *this;}
>>888 あなたの読み間違いではないと主張したいなら出典を挙げられるのがよいかと。
>>888 右辺と右辺値を混同しているとかじゃない? 右辺値と右辺値参照も違う概念。
右辺値 (というか prvalue) が完結式の終わりで解体されるのは保証された動作だけど、
std::move でキャストした結果はあくまでも参照を右辺値参照として返すってだけで
元のオブジェクト (この場合は y) は依然として左辺値だよ。
y のデストラクタが呼ばれるのは y のスコープの終わりであることは保証される。
>>892 >y のデストラクタが呼ばれるのは y のスコープの終わりであることは保証される。
なるほど。
でも結局、
T x;
T y;
x=move(y); //(1)
と書くと、(1) の部分で、
x.operator=(yを右辺値化したもの); //(2)
が行なわれて、
yの生存期間が終わる地点で、yのデストラクタであるところの y.~T() が呼び出される、
ということになることは間違いなのですね。
つまり、(2)が行なわれたら yはもはやmove後なのだから、yのデストラクタ呼び出しが
省略されるということではなく、yのデストラクタは絶対に必ず呼び出されるわけですね。
だから、T::operator=(T &&a) は、T::operator=(T &&a)の処理が終わった後に、
コンパイラによって yのデストラクタが呼び出されることを前提に処理しなければならない、
ということになる。
>>893 誤字訂正です:
誤: ということになることは間違いなのですね。
正: ということになることは間違いないのですね。
>>893 そう。 move assignment operator と呼ばれてはいるが
右辺値であるということがわかる以上の違いはない。
ムーブは寿命を左右せず、内容の状態がどうなるかは実装次第。
具体例で言えば std::unique_ptr はムーブ後には空になる (メンバ関数 get は空ポインタを返す) ことが保証されるが、
std::string は (新たな内容が与えられるまでは) 未規定の値になる。
右辺値参照が導入されたのは C++11 からで、
デストラクタのタイミングが変わってしまうような変更を入れられるわけがない。
C++で15年ぶりにプログラミングをすることになったんだけど、 C++11以降のことは何も知らないのでまずは復習もかねて勉強することにした 今でもbjarneの本が初心者にとって一番のテキストなの? それとももっとシンプルで分かりやすい本が出てるのでしょうか?
>>895 今考えてみれば、条件分岐の中だけでmove代入される場合も有るからかも知れませんね。
昔のC++知ってるならとりあえずEffective Modern C++.でいいんじゃないの
>>896 本は読者との相性があるから一概には言えないが
俺的にはやっぱ禿の本だな
変に手加減してこないところに安心感がある
ただし「プログラミング言語C++第4版」は
あくまでC++11で、C++14以後には触れていないので
構造化バインディングやコンセプトは学べない
俺はこのあたりはここやQiitaできっかけだけ拾って
あとは規格票や
https://cpprefjp.github.io/ で憶えてる
>>896 C++ はごちゃごちゃした歴史的事情を継ぎ接ぎして出来ているので
説明を整理しようとするとかえって事情がよくわからなくなる。
どう頑張ったってそんなに簡潔にはならんよ。
場当たり的に追加された変則的なルールでも
実際に挙動に絡んでくるのなら知っておくしかしょうがないし、
きちんとした説明はそれなりの分量にもなる。
おそらく
>>899 が述べる「変に手加減してこない」というのはそういう意味だと思う。
ビャーネの本、章の構成がよく分からんのだけど何がどうしてああなったん
bj氏の本のダブルディスパッチの部分と、次のVisitorの部分、 どっちもよく分からなかった。 まず、前者のShape&の引数が何のためにあって、どういう役割を果たしているか 誰か教えて。
>>903 プログラミング言語C++第四版 日本語版の
p.653, 22.3.1 ダブルディスパッチの辺りから。
bool intersect(const Shape&);
関数が無くてもこの例だと動作すると思うんだけど、
なんなん?
今でも「ロベールの C++ 入門講座」で学ぼうとしているらしいやつを Teratail や Qiita でたまに見るぞ。 C++03 と C++11 でほとんど互換性は維持されてはいるはずなんだがちょっとは非互換もあるし、 残されている機能でも今となってはあまりお勧めできないということもあるから なるべくなら新しい本のほうがよいとは思うんだが、 俺自身が読んだことがある本が古すぎていまどきの良い本が全然わからん。
>>904 メンバーアクセス演算子によるメンバの選択は抽象クラスなら動的 (仮想関数テーブルを辿る) だが、
引数を元にしたオーバーロード解決は静的型 (static type) の情報が元になる。
静的型はあくまでも Shape だから一旦は Shape& で受けて
オブジェクトと引数を入れ替えてもういちど intersect を呼び出すことで両方とも動的な型でディスパッチすることになるんだよ。
普通はメンバアクセスの側だけが動的ディスパッチだから二つのオブジェクトについて動的ディスパッチをするには
こういうトリックが必要になる。 ふたつの動的ディスパッチをするからダブルディスパッチなの。
>>907 なるほど。
Shape x, y;
x.intersect(y);
とした場合、x の方は仮想関数で振り分けられるけど、yの方はそんな機能が無いから
ということのようですね。
>>980 これは分かりにくかったかも知れません。
void func(Shape &a, Shape &b)
{
x.intersect(y); //(1)
}
Circle c{xxx};
Box b{xxx};
func(c, b);
のような場合に、(1)において、x の部分は仮想関数によってC++のもともとの機能で
実行時の型によって動的に振り分けできるが、y については、仮想関数では
そのような意味では振り分けできないから特殊な方法が必要になる、ということですね。
>>909 訂正:
誤: void func(Shape &a, Shape &b)
正: void func(Shape &x, Shape &y)
モジュールはヘッダファイル・ソースファイルに代わるものと聞きました これからは今までインクルードしていたものは全てモジュールにすればよいのでしょうか また、グローバル変数のみのヘッダファイルや、定数のみのヘッダファイルも モジュールにした方がよいのでしょうか ビルド時間が速くなるそうなので気になっています
>>909 ideone に動くソースを貼ってください、全然意味がわかりません
>>911 時期尚早だと思う。
現状の gcc ではオプションに -std=c++20 を付けるだけではモジュールは有効にならず、
明示的に -fmodules-ts を付ける必要があるようにしてあるので、普段使いするにはまだ早いという意図を感じる。
ドキュメントにはまだ完璧じゃないと書いてあるし。
(他のコンパイラの状況は知らんけど。)
それに C++20 の段階ではモジュールの基礎の基礎が決まっただけで
標準ライブラリすらモジュールとして再編できていない。 一応は C++23 でやることになってるけど
現在の C++ の規格は三年ごとに話がまとまった分を入れる、
つまり出来てない分を完成させるために期限を延長したりはせず三年後に先送りするという運用なので
C++23 がどこまで出来るものなのか全然わからん。
標準ライブラリを再編していく内にモジュール機能の問題点が発見されたりするかもしれん。
個人的に遊ぶ分には色々とやってみてわかったことはどんどん発信してほしいけど、
製品レベルのプロジェクトではやめておいたほうがいい。
>>913 msvc2022なら、と思いましたがこちらもモジュールはオプションで試験段階のようでした
もう少しvcの更新を経てから新規の小さいプロジェクトで試してみようと思います
MSは怪しい機能は/std:c++latestにしてるよな
C++17のfilesystemもそうだったけど 練りきれてない未完成品を無理に入れるのやめて欲しい バグ出ししたいんなら拡張規格かoptionalとして出してみて 標準のmandatoryにするのはしっかり固まってからにしろやって つーかSTLもboost由来のもISO以外のところでそこそこユーザに揉まれてから来たものだろ 開拓は標準規格の役目じゃねえよ
完璧になるまで練ってたらいつまでも進まんから三年ごとに出来た分を規格に入れるという方針に変更されたんじゃないか。 不格好でも不完全でも今使えることが大事だというのは元々の理念だし。 未完成はともかく欠陥報告を乱発するのは良くはないけどさ。
使ってる所だけ直せばいいライブラリと違って(だからって良いわけじゃないけど) モジュール作り込んでからやっぱdefectでしたって言われたら困るからなあ
使うだけの標準ライブラリと、モジュール自作する時の仕様のつもりだった
C++17の時点ではfile_clockがなかった
その昔、iostreamというのがあってだな 皆阿鼻叫喚の断末魔の雄叫びを上げたもんじゃった
printfやscanfに毒舌三昧してる人に対して持っていた、お暇な方ですねという思いが蘇る
ファイルシステムやらスレッドやらはシステム (OS) 側の都合があるからなぁ。 細かいことは環境依存の機能を使えという前提で 標準ライブラリを最小限にとどめるのは C の時代からの基本的な姿勢だっただろう。 環境依存だからこそ標準で吸収しておいてくれという気持ちもあるし、 現状が良いとも思わんけど…… なんというか…… C++ ってそういうもんだろと思って納得してるから不満には感じないな。
iosteamはいかにもC++初心者がやりそうな「オペレータをオーバーロードできるから 見た目イカすちょっとシャレた表記法にしようぜ!!」っていう厨二スピリット全開だったからな でてきた時点で「あ、これはクソなやつだ」ってわかったよ
C with classesを始めようとして たとえばと始めたことをずいぶん後になって 鬼の首を取ったようにキリッ
演算子チェーン自体は別に悪いもんじゃない iostreamがクソなのはそこじゃない
でも競プロで何も考えずにcin >> N >> M;とかできるでしょ
なにかとiostream叩かれやすいけど よく聞いてみると大した批判ではないよね常に 聞くに値するiostream批判ってお目にかからないね
iostreamが本当にクソならイカした再実装はあるだろう? まさかcstdioとか言わんでくれよ
まあstd::cout << foo << bar;がつい最近まで規格上未定義動作だったのは擁護のしようがないけどな
iostream が設計された当時は I/O のための専用の言語機能が 必要という論調があって、 Bjarne Stroustrup 氏はそれに抵抗して 当時の C++ の範疇でライブラリを作ったという経緯がある。 ここで抵抗しなければ入出力用の文法が (ライブラリとしてではなく) 言語機能として導入することになっていたかもしれないと思うと iostream にある粗くらいは許せてしまうなぁ。 少なくとも printf みたいな型チェックがガバガバなのは C++ 的に 放置できなかったし、バッファリングと書式化をまとめつつ拡張やカスタマイズが可能で I/O 以外も含めてストリームというインターフェイスを一般化するというのは 当時としてはこれ以上考えられない素晴らしいデザインだと思う。 ひとつこれは (iostream 設計当時でも) どうにかできただろうと思うのは 書式の変更 (マニピュレータを使うなど) をしたら陽に戻すまではそのままというのが良くなかった。 スコープを抜けたらリセットできるような方法が標準で欲しかった。 (boost にあったような気がするが名前を忘れてしまった……。)
ステートはクソで出来るだけ無くすべきっていう現代の常識が当時はなかったからな 書式をストリームのステートにしてしまったのは今思えば大失敗だがあの時代は自然な設計だったんだろうな
>>934 foo, bar がどのように定義されていたらその式が未定義動作になるの?
批判する者にその資格が無いってパティーン多々あるよな iostream批判するやつだって じゃあどんな素晴らしい入出力ライブラリを用意したの? 実装したの?どこの誰がどれだけ使ってるの?っていう タダ飯喰らいがかーちゃんのご飯批判してるようなこと
未定義じゃなくて、引数の評価順が未規定だったって話では?
>>937 何だろうと未定義(C++17以前)。なぜなら一つの式の中でstd::coutを2回変更してるから
(a+=1)+=1とか++(++a)とかも同じ
この大欠陥が見つかったせいで、式の中の評価順は基本コンパイラの好き勝手にしていいというCからの伝統を一部諦める羽目になった
>>940 foo, bar の評価順が未規定だった件を未定義動作と勘違いしてるのか。
https://cpprefjp.github.io/lang/cpp17/expression_evaluation_order.html cout に対する操作は関数呼び出しの内外の順序付けが入るから未定義動作にはならないよ。
>>940 (a+=1)+=1 も ++(++a) も未定義動作にはならないよ。必ず a が 2 増えて、 a への参照が得られる。
もっというと同じ2項演算子が複数でてきたら左から評価では? 数学と同じ
cout<<a<<b; の場合、左結合なので、評価順序は、 (cout<<a)<<b; となるが、aとbの中に関数や演算子が書いてあるような場合、 それがいつ評価されるのは実装依存だったような気がする。つまり、 operator<<(operator<<(cout,a),b); みたいに評価はされることは決まっているが、aとbの評価が、aが先かbが先かは 決まってない、というような話。もっと言えば、cout自体の部分が式や関数になって いる場合も、cout,a,bの評価順序が決まって無いかも。
>>945 もっというと、
x+y;
の場合、xとyのどちらが先に評価されるかも決まってない。
未規定の動作(unspecified behavior)と未定義動作(undefined behavior)は違うよ
>>945 ,946
なるほど言わんとしてることは分かったが
左から順に評価するのが当たり前なのでは?
つまりcout, a, bの順
>>948 実は、x86などでは、スタックが、メモリーアドレスの大きい方からから小さい方
に成長するようになっているので、引数は右側から左側に評価した方が効率が良い。
そのため、逆さまに評価する処理系があっても不思議ではない。
ちょっと前までの規格では単一式(≒セミコロンとセミコロンの間)の中の評価順は基本的にコンパイラが好き勝手に弄る事が許されてた 例えばa[++b]=cとかはヒトの常識的にはbをインクリメントしてからa[b+1]にcを代入するけど、別にa[b+1]にcを代入してからbを増やしたって構わない(この前のどっかでa[b+1]を参照してればその方が最適化したら効率的かもしれない) そんな感じで最適化に都合がいいように評価順には寛容すぎるほど寛容だったんだが、カオスを防ぐためのルールがあって、それが「単一式で同じオブジェクトを2回変更したら未定義」というもの 例えば(a+=1)+=1はどっちの1を先にaに足してもいいが、そういう自由度がある時点で未定義というルールになっていた もっと分かりやすい例だと(a+=2)*=3は最初のaが1なら常識的には9になると思うけど、評価順ルール的には3を先に掛けてから2を足して5にしたっていい 9か5の二択で済むこれはマシな方で、ポインタが絡むと収拾がつかなくなるから、同じもん2回以上書き換えたらもう知らん未定義じゃってのがCとちょい前までのc++の規格の趣旨だった で、この話をさっきのiostreamに持ち込むと、operator <<はconstメンバー関数じゃないので、cout << foo << barはcout << fooと、(cout<<fooの戻り値==coutの参照) << barの2回のcoutへの変更を順序は不確定な単一式でやってることになる。つまりさっきのaと同じように未定義動作って事 (cout <<fooを先に実行しないと戻り値確定しないからこっちが先に決まってるのでは?と思うだろうけど、規格の文言上はcout <<fooの戻り値を「予測」して<<barの適用を先にやったって構わないのである。そんな病的なコンパイラがたまたま実在しなかったから今まで問題にならなかったんだろうけどね) という話がrangesのパイプでoperator|のチェーンの検討をしてるときに発覚してみんな真っ青になって慌てて評価順のルールが見直されたっていう、まあアホ臭い話でした 幸い病的な最適化コンパイラが生まれる前だったから規格文言だけの話で実害はない
aが1のとき(a+=2)*=3が5に成り得たと書いているがほんまかいな?
9か5かってのは説明上の話で、実際は未定義で鼻から悪魔だから9でも5でも0でも-1でも42でも4394967295でもどんな可能性もあった 今の規格では必ず9になった
operator<<が触ってるcoutのメンバ変数やグローバル変数にスカラーオブジェクトが一切含まれてなければ関係ないけど普通はそんなはずは無い
テキストがバラけたり変数の並び順を変えられなくてi18n対応が困難になるのがiostreamの一番の問題かな
>>950 実際どっちが正しいかは知らんが説明がよくわからん。
cout << foo << bar の例えに (a+=2)*=3 を持ってくるのは正しいのか?
>>950 > それが「単一式で同じオブジェクトを2回変更したら未定義」というもの
C++11 より前のシーケンスポイント(副作用完了点よるルールの話だとしても関数呼び出しの前後には
シーケンスポイントが入るので cout の operator<< で未定義動作が起こるような話にはならない。
>>950 「rangesのパイプでoperator|のチェーンの検討をしてるとき」とか言ってるから
本気で C++17 改定前の話をしてるっぽいなぁ。
> それが「単一式で同じオブジェクトを2回変更したら未定義」というもの
ここから間違い。 C++11 以降は "sequenced before" の順序関係に基づくルールになっていて、
そんな大雑把なルールではない。
> 例えば(a+=1)+=1はどっちの1を先にaに足してもいいが、そういう自由度がある時点で未定義というルールになっていた
C++11 時点で代入式の値取得は代入より後になると規定されているよ。
https://timsong-cpp.github.io/cppwp/n3337/expr.ass#1 > In all cases, the assignment is sequenced after the value computation of
> the right and left operands, and before the value computation of the assignment expression.
関数呼び出し前後に順序関係もある。
https://timsong-cpp.github.io/cppwp/n3337/intro.execution#15 > When calling a function (whether or not the function is inline), every value
> computation and side effect associated with any argument expression,
> or with the postfix expression designating the called function, is sequenced before
> execution of every expression or statement in the body of the called function.
どなたか、clangコンパイラのソースコードで、main()関数がどのソースファイル にあるか分かりませんか?
>>960 もちろんgrepはしていますが、
test用のソースコードなどに大量に出てきてしまうのでどれか分からないのです。
探しているのですが、むしろ、clangコンパイラ自体のmain関数は存在して
無いのではないかと思えてしまいます。
>>961 grepでtestっぽいのを除外していけば見つけられると思うけど、
スマホでgithub見た感じdriver/tools/driver.hppじゃね
このコードでfunc(a)だけがコンパイル通らないんだけどどう対策すれば綺麗な感じになる? ユニバーサル参照の受け取りのとこでT=int&がstd::integralを満たさないのが原因なんだけど integral_or_lrefコンセプト作るしかない? #include<utility> #include<concepts> template<std::integral T> void func(T&&); int main(){ int a=0; func(0); //func(a); func(std::move(a)); }
超初心者+わかりにくい文章で、ごめんなさい。 今までは、.NetFramewor4.72でWinFormを使って実装していました。 今、.Net6.0 の WinFormで実装する必要が出てきたので .Net6.0 で実装しています。 .NetFramewor4.72 でWindowsBaseの参照の追加で使えていた System.Windows.Threading.Dispatcher が .Net6.0 では、「依存関係」の「COM」で設定しようとしても、 WindowsBaseが表示されず、WindowsBaseを設定できなくて System.Windows.Threading.Dispatcherが使えなくて、困っています。 同じような課題を諸先輩方は どのように解決されましたか?
>>964 参照を剥がすのを入れるのが常道じゃないかな?
template<class T>
requires std::integral<std::remove_reference_t<T>>
void func(T&&);
>>966 大変失礼しました。
アドバイスありがとうございます。
そういうとき脳死でstd::decay使っちゃうけどあんま行儀良くないかな
>>962 ありがとう。関数名が main() ではなく、
clang_main()
なんですね。
cmakeすると、これがすぐ呼び出されるような main() 関数が
作られるようです。
cmakeがどういう仕組みでそうやっているのかは分かりませんが。
>>962 古いWzEditorのgrepを使ってるんですけど、除外フォルダが指定できないんです。
何かいい方法は有りますかね。
どっちかってーと リンカで実行時のエントリポイントを細工してるんじゃないのかな?
追加質問です。 llvm のソースの中に、以下の様に、 配置 new に似ていてもそれとは違うような new 演算子の使用方法が 有りますが、分かる人いますか? 例えば、 new (2) CatchReturnInst(CatchPad, BB, InsertBefore); は、配置 new の new (p) T(引数列) に似ていますが、 p の位置は、アドレスを指定することになっているのに、 「2」という整数値を指定しています。 llvm-project-main/llvm/include/llvm/IR/Instructions.h の class CatchPadInst : public FuncletPadInst {・・・} の中の static CatchPadInst *Create(Value *CatchSwitch, ArrayRef<Value *> Args, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { unsigned Values = 1 + Args.size(); return new (Values) CatchPadInst(CatchSwitch, Args, Values, NameStr, InsertBefore); } class CatchReturnInst : public Instruction {・・・} の中の static CatchReturnInst *Create(Value *CatchPad, BasicBlock *BB, Instruction *InsertBefore = nullptr) { assert(CatchPad); assert(BB); return new (2) CatchReturnInst(CatchPad, BB, InsertBefore); }
>>971 ごめん、tools/driver/driver.cppだった。321行目あたりにmainあるけどこれじゃないの?
>>972 msysとかgit bashとかwslのgrepを使う、じゃダメ?vscodeでも除外設定はできるけど
>>975 以下の様に、new (Us) CatchReturnInst(引数列)は、
Userクラスの operator new(Size, Us) を使っていて、
で、Usには、アドレス値ではなく、Use 型の個数を入れるようです。
通常の operatoe new()では、第二引数はアドレス値です。
class CatchReturnInst : public Instruction {・・・};
class Instruction : public User,
public ilist_node_with_parent<Instruction, BasicBlock> {・・・};
void *User::operator new(size_t Size, unsigned Us) {
return allocateFixedOperandUser(Size, Us, 0);
}
void *User::operator new(size_t Size, unsigned Us, unsigned DescBytes) {
return allocateFixedOperandUser(Size, Us, DescBytes);
}
void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
unsigned DescBytes) {
・・・
uint8_t *Storage = static_cast<uint8_t *>(
::operator new(Size + sizeof(Use) * Us + DescBytesToAllocate));
・・・
}
>>976 >ごめん、tools/driver/driver.cppだった。321行目あたりにmainあるけどこれじゃないの?
そのサイトは、mirrorサイトで「legacy」とされ、だいぶ古いバージョンなんです。
最新バージョンのソースでは、driver.cpp には clang_main()しかないと思います。
cmakeすると、buildフォルダに、
int main(int argc, char *argv[]) { return clang_main(argc, argv); }
のような一行の関数が出来ます。
>>978 (1) 本当の clang の main() 関数本体 :
(llvm-project-main/clang/tools/driver/driver.cpp):
int clang_main(int Argc, char **Argv) {
・・・
・・・
}
(2) clang_main() を呼び出す main() 関数 :
(llvm-project-main/build/tools/clang/tools/driver/clang-driver.cpp):
↑
build は、cmake の destination ディレクトリです。
int clang_main(int argc, char **argv);
int main(int argc, char **argv) { return clang_main(argc, argv); }
↑本当にこんな風に一行の関数になっています。恐らく、cmake が
生成したものと思われます。
>>978-979 なるほどすまんかった。
たまたま古いソースをみてたからmainを見つけられたんだね。勉強になりました。
>>968 やはりrequiresを1行足すしかないか...
template<allow_ref<std::integral> T>
void func(T&&);
とでも書きたかったけど、コンセプトを受け取るテンプレートが書けないっぽいから諦めた
clangのソースで、CPUのマシン語を生成している場所を調べていて、 X86AsmPrinter クラスや X86MCInstLower クラスがそれに強く関与していることが分かって きました。 X86AsmPrinter クラスや X86MCInstLower クラスは、お互いに参照されてますが、 この2つのクラスは、いずれも「作られている場所」が見つかりません。 「作られている」とは、new X86AsmPrinter や、X86AsmPrinter a;、 new X86MCInstLower や X86MCInstLower b; のようにしている場所です。 どなたか分かりませんか?
>>982 すみません、多分、以下の部分ですね。
これで、new X86AsmPrinterしたアドレスを、getTheX86_32Target()やgetTheX86_64Target()
が返した Target クラスのシングルトンのインスタンス xxx に対して
xxx.AsmPrinterCtorFn = アドレス;
のように記録しているようです。
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeX86AsmPrinter() {
RegisterAsmPrinter<X86AsmPrinter> X(getTheX86_32Target());
RegisterAsmPrinter<X86AsmPrinter> Y(getTheX86_64Target());
}
template <class AsmPrinterImpl> struct RegisterAsmPrinter {
RegisterAsmPrinter(Target &T) {
TargetRegistry::RegisterAsmPrinter(T, &Allocator);
}
private:
static AsmPrinter *Allocator(TargetMachine &TM,
std::unique_ptr<MCStreamer> &&Streamer) {
return new AsmPrinterImpl(TM, std::move(Streamer));
}
};
/// TargetRegistry - Generic interface to target specific features.
struct TargetRegistry {
・・・
static void RegisterAsmPrinter(Target &T, Target::AsmPrinterCtorTy Fn) {
T.AsmPrinterCtorFn = Fn;
}
・・・
};
なんかコンセプト以前にテンプレートにもあまり慣れてなさそう
間違えました。 xxx.AsmPrinterCtorFn に登録しているのは、new X86AsmPrinterの アドレスではなく、 RegisterAsmPrinter<X86AsmPrinter>::Allocator(・・・) のアドレスのようですね。 そして、このAllocator (==関数)を呼び出すと、new X86AsmPrinter を行なえるようです。
関係ないけどあんまりnewせんほうがええよ それしかないと思ってるならちょっと古い感じ
あんまりデータメンバに直アクセスしないほうがええよ あんまりグローバル変数使わんほうがええよ あんまりSendMessageを直に使わんほうがええよ あんまりナマポ使わんほうがええよ あんまりアセンブラ使わんほうがええよ あんまりC++使わんほうがええよ ラップしろってことだろうけど 一切離れたやつはもうC++使いじゃない
>>986 イリノイ大学のclangやLLVMの開発者に言ってください。
コンパイラでは最先端かも知れませんが。
threadがあんなに使いやすくなっているのは ひとえにtemplate-parameter-packのおかげ
>>950 の話は終わりかな?
レスついたけど反論がないようだけど
仕事ハネた後のヨレヨレ状態で見てるから 長文()を読もうとすると寝落ちしかねない
VC++ や GCC で <cstddef> をインクルードすると、 std の明⽰的修飾、using 宣言、using 指令がなくても size_t が使えるのですが、これは C++ 標準の仕様ですか?
>>995 いいえ。 未規定です。
std 名前空間内で定義されることは当然に保証された動作ですが、
グローバルには定義されてもされなくてもかまいません。
逆に言えばグローバルに定義されていることはありうると想定する必要があります。
(なので自分が定義する名前がそれに衝突しないようにするべきです。)