C++相談室 part139
■ このスレッドは過去ログ倉庫に格納されています
次スレを立てる時は本文の1行目に以下を追加して下さい。 !extend:on:vvvvv:1000:512 C++に関する質問やら話題やらはこちらへどうぞ。 ただし質問の前にはFAQに一通り目を通してください。 IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。 前スレ C++相談室 part137 (正しくはpart138) http://mevius.5ch.net/test/read.cgi/tech/1535353320/ このスレもよろしくね。 【初心者歓迎】C/C++室 Ver.103【環境依存OK】 https://mevius.5ch.net/test/read.cgi/tech/1530384293/ ■長いソースを貼るときはここへ。■ 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 長時間のプログラム終了を手元のスマートフォンで確認したい(メールなど)という願望からそういったプログラムを書きたいんですがさっぱり分かりません 開発環境はvisual studioです 普通に、Linux コマンドを並べたら、1・2の順番で実行される。 PowerShell でも良い command_1 ; command_2 ; コマンド1 が終わったら、メール送信するなら、 command_1 ; メール送信 ; 複雑な処理は、コマンド・シェルスクリプトよりも、Ruby などで作る方がよい >>782 今は知らんけど、数年前だったら、メール送信は知識が結構必要だった。 SendMail Transfer Protocol なるものを使うんだけど、それを便利に発行できる 関数なりCUIプログラムがあれば使えるんだけども。 >>784 Linux だったら、aaa.txt に以下のような内容を書いて、 --------------------------------------- From: my@mail.address (あなたのメールアドレス) To: foo@example.com Subject: This is test mail. (ここに空行を入れる。ここまでがヘッダ。ここから先がボディ) メールの内容 .(ドットのみの行を入力すると終了) --------------------------------------- $ sendmail foo@example.com < aaa.txt とすると後れるらしい。sendmail は、CUI コマンド。 だから、VisualStudio からだと、 system( "sendmail foo@example.com < aaa.txt" ); とすれば、sendmail コマンドが存在しているなら動作する。 >>780 >>774 で言っている関数の外側の環境って意味だよ。それがクロージャの中なのは当然。 いいかげん、元の「関数を渡す」って話からずれまくっているが、結局どういうことを言いたいんだろう。 >>779 いやだからc++なら継承でメソッドでオーバーライドする方が わかりやすいし、資源も管理しやすいんじゃない?って話。 他の言語にあるからみたいな理由で合わんもの入れてもなということなんだけど。 >>787 >結局どういうことを言いたいんだろう。 クロージャ=関数 特に()のオーバーライド(int Hoge::operator()(int a, int b) { ... })までやった場合、 HogeクラスのインスタンスhogeはC++の構文的にも関数同然に機能の呼び出しを行える (関数オブジェクトとかファンクタとか呼ばれるやつになる >元の「関数を渡す」って話 クロージャ=関数なのであるから、クロージャを、クロージャを受け取る他の関数またはクロージャに渡すという話、-- (A) 継承を使う場合のsome_typeのベースクラスをsome_typeのベースクラスを受け取る他の関数に渡すことに対応する --(B) この場合、クロージャを使うやり方に対する継承を使うやり方のデメリットは… 、と静的型チェック周辺の話に持っていくことができるが、その前に(A)や(B)が共通認識になったのか、それとも理解不能なのかどうか確認しておきたい >>789 >クロージャ=関数 そういう前提で言っていたのか? ID:AQ4G8Wg10は明らかにクロージャと関数を使い分けているようだが。>>766 >>773 じゃあそこは了解したとして、(A)(B)の条件の下でもう一度>>768 の質問をするよ。 関数の静的型チェックとクロージャの相性が悪いところってたとえばどんな? デリゲートは、オブジェクトを参照キャプチャするクロージャと同じ (マルチキャストみたいなおまけ機能もファンクタとして実現したクロージャになら追加できる ファンクタとしてクロージャする分には型安全性も同等なので、ファンクタとデリゲートは混同上等のはず… >>891 >関数の静的型チェックとクロージャの相性が悪いところってたとえばどんな? 知らん >>766 はクロージャの実現方法について黒魔術的な何かを想定しているのではないか… C++におけるクロージャの簡単な実現方法はファンクタ、であって、ファンクタには特に型安全や資源解放に関するファンクタ固有の問題は無いと思う 何しろファンクタは普通のクラスHogeの普通のインスタンスhogeとして>>748 風に書けるので… 一方、広義のクロージャは、変数を束縛するしくみ=クロージャなので、型安全という概念をそもそも含まない この広義のクロージャをC++上で実現しようとしているのだとしたら知らん >>788 > いやだからc++なら継承でメソッドでオーバーライドする方が > わかりやすいし、資源も管理しやすいんじゃない?って話。 だからそんなことはないと私は述べてる。 ラムダ式を使いたいときというのはほとんどの場合は小さな関数を作りたいときなんだよ。 それも一回しか使われないような使い捨てのものをだ。 使い捨てるのならば、別の場所で定義して (名前を付けて) から使うのはまわりくどい。 わかりにくくて管理しづらくなる。 もちろん、場合によってはラムダ式が適さない場合だってある。 そういう場合まで何もかもをラムダ式に置き換えろってんじゃないだ。 ラムダ式が適しているときにラムダ式を使えってだけのことで、しかもそれは案外に多いってことだ。 ああわかった。 >>776 ではクロージャと関数を区別して書いていたのに対して、>>777 は単に >クロージャ=関数 と言いたかっただけなんだな。 アンカー間違えた。>>776 じゃなくて>>774 か。 訂正orz 誤: 変数を束縛するしくみ=クロージャ 正: 変数を束縛して作った関数(ただし束縛すべき変数のリストが空のときもある)=クロージャ 型安全な言語なら型安全に、そうでない言語でもそれなりにやっぱクロージャ=関数ェ、 >>794 >ラムダ式を使いたいときというのはほとんどの場合は小さな関数を作りたいときなんだよ。 >それも一回しか使われないような使い捨てのものをだ。 ここが自分の感覚と違う。 ラムダ式を使いたい時ってもう少し動的な関数作成に関わる場合という感覚。 単に名前付けを省略したいくらいならどうとでもなると思うし、個人的にはそんな興味ない用途。 C++のラムダ式でどうやって動的関数生成なんかやるの? 何かを根本的に勘違いしてるとしか思えない jsのノリをc++に持ち込もうとして、 面倒だってぶつくさ言うやつ定期的に現れるよな なぜc++使おうとしているのか、自分を見つめ直した方がいいぞ さてはオヌシ、Javascript使ったことござらんな。 new演算子について教えてください。 自分で定義したクラスをインスタンス化してグローバル変数として扱いたいです。 グローバル変数には実体がないといけないと思うのですが、new演算子は ポインタにしか使えないですよね? この場合どうしたらいいでしょうか newなんか使わずそのままグローバル変数として myclass mc; とか定義すればよい >>802 いやだからc++でなんでラムダ式とか入れちゃうのかっていう話をだね。。 jsのノリを無理やり入れたがってるのはc++の仕様の方で別に俺は入れたくない って意見なのだが。 >>810 オブジェクトとクロージャはメカニズム的には似たようなもんだ という感覚は言語処理系に明るい人の感覚としては元々ある。 C++ にラムダ式が追加される前に書かれたこの記事が面白いよ。 "クロージャとオブジェクトの微妙な関係" http://www.itmedia.co.jp/enterprise/articles/0703/29/news069.html JavaScript の「オブジェクト」だって、その内実は環境への操作だ。 つまりはクロージャを基礎にしてオブジェクトに見せているんだから、 その逆をやる言語があったって別に不自然なことではなかろ。 >>809 なるほど! 教えてもらったとおりnew使わないでできました! クラス・クロージャは、同じ。 関数・メソッドから、引数渡しでもないのに、外側の変数を参照できるから Ruby のブロックがクロージャ。 ブロックの外側の変数が参照できる 一方、Ruby の関数は、外側の変数を参照できないから、 JavaScript, Python, PHP よりも、すごい強固 Ruby だけは、クロージャの外に、関数をスコープを作っている。 さらに関数の外側がクラスで、クラスの外側がモジュール モジュール > クラス > メソッド(関数) > ブロック(クロージャ) Ruby 独特の構造! エディッタだけで、Visual Studioコンパイル済まで持って行けた。。。 サンタさんがくれた素敵な奇跡。だからその瞬間を宝物にして、書き込みしたくなっちゃうんですね はちみつ餃子さんってC++を使ってる業務に就いてるんですか? 前にも書いたことあると思うけど、ワイは完全に趣味でやっとる人やで 理解が深まった。ありがとう。 しかし理解すればするほど、c++ならやっぱクラス生成でよくね?って気になるが。 >>821 繰返して述べるが、 C++ のラムダ式は単純なクラスの定義と使用を同時に出来る構文糖でしかない。 何故か「クロージャ」と混同した書き込みがあるが (もちろんいわゆるクロージャの概念からおおいに影響は受けているのだろうが) C++ のラムダ式は C++ に新しい概念を導入するものではない。 c++の属性構文が出来たけどc++17で不明な属性は無視するという規定が出来たからには、コンパイラによっては独自の属性があるの? > C++ のラムダ式は C++ に新しい概念を導入するものではない。 これはさすがに言い過ぎ 関数型のリテラルという概念は C++98 にはなかった だから C++11 になったとき新しく憶えた 既存の概念の組み合わせでできているから 割とすんなり憶えられたけどね VC++で[[deprecated]]使ったら警告じゃなくてエラーになっちゃう。 いやまあ正解なんだけどさ・・・ >>827 ん、cl.exe の 19.16.27024.1 では通るが? つーか、[[deprecated]]って書いてある関数を使っても警告しないのはつまらない Emscripten で、マウスの動きに合わせて JS の canvasに直線を描いたりする ようなGUIプログラムを作って試していて、local auto 変数に確保した 16バイトの char 配列に、sprintf で色の #RRGGBB の文字列を合成 して JS に渡して canvas の context の style に直線の色を設定していた。 で、同時に、KeyDown イベントでで20文字ほどのグラフィック文字列を出して いた。なお、そっちの方でも、全く同じ関数を使って、上記の色の文字列 を合成していた。 すると不思議なことに、KeyDownイベントで文字列を書いた後は、 必ず、直線の方の色が変わってしまう。必ず青色で書くようにしているはずなのに。 ログをとってみると、 char szBuf[16]; sprintf(szBuf, "#%02X%02X%02X", r, g, b); で szBuf に対して、最後の 0終端文字が、書き込まれていないことが判明。 よく見ると、KeyDownイベントで色のためではなく、出力したい 文字列そのものの文字の一部が直線描画の方の szBuf の #RRGGBB の直後に 残ったままコピーされているように振舞っていた。 ためしに、sprintf() の命令の直前に、memset(szBuf, 0, 16); とすると 正常化することも確認した。 Emscripten のライブラリの不具合だろうか? char szCol[16]; memset( szCol, 0, 16 ); memset( szCol, 'W', 10 ); szprintf( szCol, ・・・ ); とした場合は、W の文字が残ったままになることも分かった。 szprintf() の直後に szCol[7] = 0; とすると、正常化することも分かった。 C++でクラスポインタにnewしたオブジェクトを配列の様に複数作りたいのですが、 エラーがでてしまいます。 ポインタの宣言 TimerParameter *_timerParameter; インスタンス化 _timerParameter[_timerSize] = new TimerParameter(time, function, one_loop); TimerParameterコンストラクタ TimerParameter::TimerParameter(ULONG time, void(*function)(), bool one_loop) { _function = function; _oneLoop = one_loop; _timeSpan = time; resetTimer(); } 自分で作ったTimerParameterクラスをnewして_timerParameterメンバに入れると以下のエラーが発生してしまいます sketch\timerState.cpp: In member function 'bool TimerState::timerSet(long unsigned int, void (*)(), bool)': timerState.cpp:14:30: error: no match for 'operator=' (operand types are 'TimerParameter' and 'TimerParameter*') _timerParameter[_timerSize] = new TimerParameter(time, function, one_loop); インスタンス化の左辺が適切でないのが原因だと思うのですが、この書き方はダメなのでしょうか? _timerParameter[_timerSize]の型はTimerParameter new TimerParameter(...)の型はTimerParameter * あと、 Type * ptr; ptr[2] = createType(); なんてやっちゃダメなのわかってる? Type * ptr; ptr = new Type[10]; ptr[2] = createType(); ならいいんだけど あと、"_"で始まる名前は処理系予約だし timeはcの標準関数にtime_t time(time_t *t);があるんでやめれ アンダーバー2つかアンダーバー+大文字で始まるものが予約されてるだけでアンダーバー+小文字で始まるのは大丈夫 vector<vector<float>> = { {1.33333334, 3.99918277}, {2.56883338, 1.29994666} } このようにvector<vector<float>>をdouble型の要素で初期化しようとすると縮小変換が必要とのエラーが出ます どうしたら縮小変換しつつ初期化出来るんですかね? >>839 >ならいいけど よくないだろ。なぜコピーさせるのか BoostやSTLのDeveloperになりたいんですけど、テンプレートを極めればなれますか? テンプレートに限らずC++を極めてるのは当然の前提として Developerとして参加するプロジェクトをどうしたいとか、どんな価値を提供できるかとかが重要じゃないかな BoostならBoost相当の性能のライブラリを作って水準に合うドキュメントと何故それがBoostに必要なのか説明する提案書を書いて提出すれば100回リジェクトされる頃には採用されるかも知れない >>847 C++をより良い言語にしたいです 今はアルゴリズムの研究をしてるのですが、C++をより良い言語にしたいと個人的に思ってるのと、自分が作った言語機能を人に使ってほしいんです >>848 Boost‥ 100回リジェクトされた頃には相当な経験が詰めるはずなので挑戦してみます >>849 C++自体を改良したいなら標準化委員会に行くかコンパイラの開発に参加しよう すばらしい、C++標準化に参加して、文字コードの扱いの混乱した現状をなんとかしてほしいw char型はwindowsがsjis、それ以外がutf8、 wchar型は64bit linuxが32bitで、それ以外は16bit、 どのプラットフォームでも同じようにつかえるchar16_t/char32_tはAPIやライブラリが未整備な上、エンディアンの問題がつきまとう、 と、マルチプラットフォームで各種文字コードの透過的な相互運用は事実上不可能な状態だからな…… そう、それな、ポータブルな保存形式はutf8で良いと思うんだけど、BOMの有無とか、冗長コードの問題とかで実際にやってみると意外と面倒なんだよね。 Windows では Shift_JIS (CP932) という前提もホント駄目な勘違い。 visual studioはいろんなエンコードに対応してるように見せかけてshift-jis前提で動いてる気がする。 デバッガでpngのシグニチャ確認したら臼ngとなるとか、コメントにπを書いたら赤の波線が出るとか。 >>856 ユーザーのコードページを変える以外に方法がないらしい。 Windowsの言語パック入れて表示言語を選択すればたぶん変わる。 まぁ、マイクロソフトも徐々にUTF8を標準サポートにする方向みたいだから、2〜3年したらVisual Studioもデフォルトがutf8になるかもね。 エンディアンの問題も、x86,ARMに続いてRISC-Vがリトルだから、流れとしてはリトルで統一ってことになるのかな。そうなったら楽でいいなw RISC CPUが出始めたときはビッグの勢いあったけど 結局リトルに収斂したな おれは昔からリトルが自然と感じてたのでいい流れだ ネットとの相性が悪いのは残ってしまうが Emscripten で Cソース中に以下のようなプログラムを作ると、MyPrintf()内の (2) で (3)の vsprintf() を呼び出そうとした瞬間に、なぜか (4) に来ずに、 (5)に戻ってきて a4 に制御が戻って来てしまうことが判明。タイマーイベント を使ってる。誰か原因の見当が付く人いない? EM_ASM( { function js_OnTimer() { console.log( 'begin of js_OnTimer()\n' ); //a1 var cl_OnTimer = Module.cwrap('OnTimer', 'number', ['number']); console.log( 'js_OnTimer(), before calling cl_OnTimer(1)\n' ); //a2 var rc = cl_OnTimer(1); //a3 console.log( 'js_OnTimer(), after calling cl_OnTimer(1)\n' ); //a4 console.log( 'end of js_OnTimer()\n' ); //a5 } setInterval(js_OnTimer, 1000); }); extern "C" int OnTimer( int a ) { OnTimerCore(); return 0; } void OnTimerCore() { MyPrintf( "begin(MyPrintf) of OnTimerCore(), %d", 123 ); // (1) printf( "begin(printf) of OnTimerCore(), %d\n", 456 ); // (5) } >>863 void MyPrintf( const char *pszFormat, ... ) { char szBuf[2048]; va_list va; va_start( va, pszFormat ); EM_ASM( { console.log( 'MyPrintf, before call vsprintf()\n' ); }); //(2) vsprintf( szBuf, pszFormat, va ); // (3) EM_ASM( { console.log( 'MyPrintf, after call vsprintf()\n' ); }); //(4) va_end( va ); } >>863 原因は、main 関数の最後に書いておいた、次のループにあった : for ( ;; ) { emscripten_sleep(36000000); // 何日間も待つ。 } このループをコメント・アウトするだけで、vsprintf() が1つ前の戻り先に 戻ってしまう不具合も、sprintf() が 0 終端文字を書いてくれない不具合も 共に起きなくなった。 このループを書いていたのは、Emscripten 1.35 で、かつ、 wasm ではなく、asm.js で試していたときに、キー押下イベント などが発生した時に Assertion failed: the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits) というエラーが出るためだった。つまり、main() 関数が終わると、 「ランタイム」(ランタイム・ライブラリ?) も終了してしてしまうので、 main() を終わらせられなかった。だから、main() の最後に、なんらかの 無限待機の仕組みが欲しくなって書いていたのだった。 現在は このループを除去しても警告が出なくなっているが、 Emscripten の Version を上げたせいか、asm.js ではなく、wasm の方を 使うようになったせいかは分からない。 なんでリトルが自然なん? あとから拡張しやすいって意味か? 加算器は下の桁から処理していって桁上げする方が自然とか、複数バイト長のワードで ビットアドレスとバイトアドレスの増加方向が同じになるとかかな。 ワードサイズが変わっても低位バイトの位置が変わらないから拡張しやすいってのも もちろんあると思う。 ハード作ってる時はビッグエンディアンの方が自然な気がするがソフト作ってる時はリトルエンディアンの方が自然な気がする まあ、FPGAと高級言語を使うようになってからは滅多に気にすることは無くなったけど >>867 cast するときにも便利。 メモリに書かれた 32BIT整数を 8BIT 整数として取得したい際など、 先頭アドレスが変わらないので、速度効率が上がりやすい。 もし、BIG ENDIAN だとそのようなときに、「3」足さないといけなく なってしまうと思う。 fstreamでリトルとビッグの切り替えってどうするの 逆にビッグエンディアンの方が自然に思えるのは16進ダンプ見てるときくらいしか思いつかない。 Uint32 u32; BYTE u8; u8 = (BYTE )u32; とするコードがあったとする。u32 を、ポインタで置き換えたいとき、 Uint32 *pUint32; u8 = (BYTE )*pUint32; と書くのも正解だが、 u8 = *(BYTE *)pUint32; と書くのも正解で、実は、後者の方が効率は良い場合があるとされる。 なぜなら、メモリから前者は4バイト読んでから上位バイトを捨てるが、 後者では最初から上位バイトを読まないから。 この場合、Little Endian だと、後者の書き方でも混乱が少ないが、Big Endian だと何を意味しているのか分かりにくくなる。というのは、 (BYTE *)のようなポインタ型への cast は、旧来の C では、アドレス値自体は 変更せずに、型だけを変更するというのが伝統的な実装だったため (ただし、C++ の場合、多重継承していた場合は、その原則を破ってアドレス値が 変化する事があるが。)。 BigEndian の場合、最後の書き方の実装に不安定要素が残るように思える。 >>836 ,>>839 ありがとうございました。 配列の実態作ったらできました! _を接頭文字で使うのは結構規模の大きいオープンソースプロジェクトのソースで メンバー変数の頭に_を使ってたのでやってました。 気を付けます。 話は少し変わるんですが、>>809 でクラスをnewせずに使うというのが書かれていますが、 オブジェクトをnewせずに使うことって結構あるんでしょうか? 普段C#やっているのですが、クラスは基本的にnewでインスタンス化して使うものと思っていたので、(コンストラクタで特に初期化処理がなくても) >>874 >話は少し変わるんですが、>>809 でクラスをnewせずに使うというのが書かれていますが、 >オブジェクトをnewせずに使うことって結構あるんでしょうか? どちらかというと、C++では new する必要ない場合は、new しないことが 良い書き方。new は、好きなタイミングで削除したいようなオブジェクトの場合 のみ使用する。構造体やクラスのメンバの中に、別のクラスのオブジェクトが含まれている ような場合は、new しないのが原則。 ある意味では、そのような習慣があるからこそ、C++ は効率が良いともいえる。 実は、new や malloc は、確保するサイズにかかわらず、大体 170 クロックほど 必要。delete や free と合わせると、合計 300 クロック必要となる。 一方、そのまま、new せずに「埋め込んだ」場合は、基本的に「0」クロック。 この差はとても大きなものとなることがある。 >>874 最初から最後まで存在し続けて、特別な終了処理が必要ないオブジェクトなら、わざわざヒープを確保して実行時に初期化する必要はないでしょ。 あと、staticなオブジェクトのコンストラクタはmain関数の前にグローバルコンストラクタから呼び出されるのだが、 これを利用して、プログラム起動時にやっておきたい初期化処理をクラス内で記述する目的に使うこともあるね。 >>875 さすがに良い書き方っていうのはどうかと思うけどな。 staticなオブジェクトにしちゃうと、初期化の順番が制御できないから、気をつけて使わないとコンパイラ依存のコードになってしまうし。 >>875 ,>>876 ありがとうございます。 このあたりのC++とC#の慣習の差異に違和感を覚えていたのですが、かなりスッキリしました。 >>877 必要な場合は new しても良い。でも、クラス Cxxxの中には、文字列の CString クラスのオブジェクトや、何らかのリストのオブジェクトが複数含まれて いたりすることも多い。それらのメンバを全て new する場合と、埋め込み でそのまま使う場合とでは、Cxxx をインスタンス化するときの時間に雲泥の 差が出てしまう。Cxxx が、5つのクラス・オブジェクトを含んでいた場合、 それらを new するだけで、170 * 5 クロックも余分に掛かってしまう。 この数値には、各コンストラクタの処理時間は含まれていないので。 この場合だと、全て new すると、850 クロックも余計に掛かることになる。 さらに、Cxxx オブジェクトがデストラクトされる場合には、合計で、この 1.8 倍程度の時間が new しない場合より余計に掛かることになってしまう。 >>872 思い出したので追加しておく。 Little Endian の場合、 >Uint32 u32; >BYTE u8; >u8 = (BYTE )u32; の代わりに、 Uint32 u32; BYTE u8; u8 = *(BYTE *)&u32; という書き方も出来て、こっちの方が、処理効率が良い場合があるとされている。 しかし、BigEndian だとこの書き方は混乱を招きやすく、かつ、処理効率も 上がらないと思われる。 総合的に考えると、Little Endian の方が処理効率が上がりやすいはずだ。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.4 2024/05/19 Walang Kapalit ★ | Donguri System Team 5ちゃんねる