C++相談室 part165
!extend:checked:vvvvv:1000:512 !extend:checked:vvvvv:1000:512 ↑同じ内容を3行貼り付けること 次スレは>>980 が立てること 無理なら細かく安価指定 ※前スレ C++相談室 part164 https://mevius.5ch.net/test/read.cgi/tech/1683600652/ VIPQ2_EXTDAT: checked:vvvvv:1000:512:: EXT was configured catchしようがしまいが、例外が起きて 処理A→B→return となるのは同じだと思うが。 その場合の検証が必要だというならどっちも必要だろ。 >>182 >catchしようがしまいが、例外が起きて 処理A→B→return となるのは同じだと思うが。 それは問題の認識がおかいし 例えば以下のコードにおいて、スレッドのゾンビを生じさせないためにはfuncB()をtry { } catch () { } は必須になる。 void bar() { funcA(); // スレッドxを起動 funcB(); // 中でbaz() → foo()の呼び出し funcC(); // スレッドxに停止シグナル発酵 funcD(); // スレッドxの終了待ち return; } このように一般に例外が飛んでくる関数にはcatchするかしないかの選択権など無い 例外安全なオブジェクト「だけ」で事が済んでいない限り、例外を受けると決めた時点でcatchせねばならない 一方、例外を生じないライブラリの使い方(関数の呼び出し方)を心掛けるかどうか。これなら選択肢がある 訂正orz 誤:例外安全なオブジェクト「だけ」で事が済んでいない限り、例外を受けると決めた時点でcatchせねばならない 正:例外安全なオブジェクト「だけ」で事が済んでいない限り、例外が飛んでくる想定であるならばcatchせねばならない >>183 それはfuncB()に失敗の可能性がある時に必ず必要な話だろ?例外どうこうじゃないじゃん funcB()が例外を投げずに古き良きintのエラーコードを戻り値で返す場合は何かが変わるの? まさか「funcBの戻り値をガン無視すればfuncCもfuncDも実行されてくれるから完璧!だから例外はクソ!」っていうゴミカスみたいな主張をしたいわけじゃないよね? >>183 それはcatchが必要かどうかの話だろ。 catchしたらテストケースが増えるかどうかという話とはなんも関係がない。 そもそも未知の例外飛んできた時点でそれを通したライブラリの例外安全性が守られてるか怪しいと考えるべき 例外安全性を守るのに例外の種類やそれが既知か未知かは関係ないだろうが、 仕様に明記した例外以外は堰き止めるのが正解だろうなあ。 思い立って結城さんのデザパタ(古いjava で記述)を総称型(テンプレート)もちゃんと使ってC++ に書き直しているけれども、 new/delete からptr::shared_ptr に書きなおすと、もう構造がわかりにくくなってしまってどうしようもない デザパタ=抽象クラスプログラミングは C++ ではオワコンなの? Visitor パターン new/delete: https://ideone.com/6d43LO スッキリ書けてきもちいい std::shared_ptr: https://ideone.com/oYzkxh 恐ろしい宣言の連発 >std::shared_ptr<Iterator<std::shared_ptr<Entry>>> iterator() { return std::make_shared<VectorIterator<std::shared_ptr<Entry>>>(v); } なんかもう書いてても意味不明 CONSTRUCTOR(CONSTRUCTOR *p) とかコピコン以外にもみたことのないコンストラクタが要求されるし >>189 スマートポインタを使わないバージョンも C++ 的にはすっきりしてない。 動的多態の必要が必要ないのに持つべきメンバ関数を強制するためだけに抽象クラスを使っていて不恰好に見える。 コンセプトの導入がだいぶん後回しになった C++ の問題でもあるんだが……。 設計理念が妥当かどうかはともかくとして、元が Java なら直訳めいた C++ への置き換えがすっきりと書けるはずがない。 ざっと見た感じだと抽象クラスとして必要なのは Entry だけかな。 ジェネリックラムダが visitor パターンで使いやすいのでそういうのが使いやすいように配慮するといいかも。 std::visit が C++ での visitor パターンのお手本だよ。 >>189 usingなりtypedefでエイリアス作れば? using Entry_Ptr = std::shared_ptr<Entry>; 面白そうだからちょっと書いてみた。大きな変更点はこんな感じ。 ・accept が受け取るのは単に Visitor の参照でいい。ここで shared_ptr を使う必要はない。 ・Visitor が受け取るのも File や Directory の参照でいい。 ・SizeVisitor もいらない。File と Directory はともに Entry の子クラスとして getSize() を実装してるんだから、無理に visitor パターンを使わなくても単に getSize() を呼べばいいだけ。 ・iterator() が返すのも VectorIterator の shared_ptr ではなく、単に VectorIterator を返せばいい。 全体的に使う必要がない場面で shared_ptr を使ってるのが目立ったと思う。 https://wandbox.org/permlink/ZBKbF5iMVpb7Looi だいぶすっきりしたんじゃない? なんかもうポインタをいじるのが面倒になったので値としてやりとりしていいやという気持ちと 標準ライブラリを積極的に活用することにしたらこうなった。 https://wandbox.org/permlink/BQCNjfdJRKWAR3dg >>193 拝読させていただきました。なるほど、関係性を示すポインタ=参照なら std::shared_ptr でくるむ必要ガない、というわけですか。 >>194 拝読させていただきました。Entry を値で持つのはいやだなあ。 dectype の使い方を学ばせていただきました。 >>194 std::size_t() あたりから読めていません。operator() をどう使っているのでしょうか? スマートポインタを使うにしても std::shared_ptr って必要? この場合は std::unique_ptr でよくない? https://wandbox.org/permlink/dMolraFpQHKzYtF3 設計思想によるけどファイルシステムを表現するという前提だと ひとつのルートディレクトリに連なる全てのエントリは実質的に一体のデータ構造なので ルートディレクトリエントリの寿命が尽きれば全て解体ってことにしたほうが簡単でいいと思う。 ハードリンクの表現とかも考えるなら事情が変わってくることもあるだろうけど……。 >>189 c++ https://ideone.com/p3li2Y ・https://ideone.com/oYzkxh を元に若干の整理を行った ・他の人と同様shared_ptrを削除 値で持てるところは単に値で持つほうがC++っぽいと思う ただ「Entry を値で持つのはいやだなあ」とのことなので部分的に残してる Javaの参照型変数をshared_ptrに置き換えようとして困るのは size_t File::accept(std::shared_ptr<Visitor> v) { return v->visit(std::make_shared<File>(this)); } ここがJavaだと単にvisit(this)で済むからスッキリするんだけど しかもこれmake_shared(this)だと多重開放するよね?? >>189 c++ https://ideone.com/2uUpwH ・https://ideone.com/p3li2Y を元に若干の整理を行った ・make_shared<File>(this)の多重開放?を修正 std::enable_shared_from_thisを使ってJavaの参照型変数っぽい使用感を得た。 ・struct this_is_private {}; これは単にコンストラクタを実質的にprivateにするためだけに使ってる https://en.cppreference.com/w/cpp/memory/enable_shared_from_this https://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const このへん参照されたし https://wandbox.org/permlink/LEl2MT7OdGIlVKC4 なんか「子クラスのコンストラクタに親クラスのオブジェクトを渡して子クラスのメンバを初期化する」(?)みたいなことができちゃってるんだけど、これってどういう仕様でこうなってんの? Wandbox上だとC++2aではコンパイルできてC++17ではコンパイルできなかったからcpprefjpのC++20の機能の一覧も見てみたけどそれらしいものはなかったし >>199 designated initializer も C++20 からの機能なんだけど……それは脇に置く。 この場合は集成体初期化に該当する。 C++17 から基底の初期化も集成体初期化で扱えるので child c{p}; というように初期化出来ていた。 更に C++20 では集成体初期化を丸括弧で書いても良いことになったので child c(p); とすることが許されるようになった。 >>198 >size_t File::accept(std::shared_ptr<Visitor> v) { return v->visit(std::make_shared<File>(this)); } > ここがJavaだと単にvisit(this)で済むからスッキリするんだけど > しかもこれmake_shared(this)だと多重開放するよね?? 多重解放(二重解放)しないことはラッパをかませて確認済みです。そう簡単に std::shared_ptr は破綻しないと信じています https://ideone.com/GUPcSu それはともかく、皆様のご意見には感謝しております。これからもお伺いさせていただいた際にはよろしくお願いいたします。 >>200 https://cpprefjp.github.io/lang/cpp17/extension_to_aggregate_initialization.html これかあ 実は「childにコンストラクタがある場合」とか「childにprivateメンバがある場合」とか「childがparentをprivate継承している場合」とかはコンパイルが通らなくてもう意味が解らなかったんだけど、それもchildが集成体じゃなくなってたからだったんだね ありがとう、勉強になった >>198 >値で持てるところは単に値で持つほうがC++っぽいと思う 時代の流れを感じさせるお言葉です。なにせ K&R1 で育った世代なので(K&R1 では構造体の実体渡しはできず、かならずポインタで渡さなければならなかった)。 C++ においても、コピコンを働かせないために const & を多用する毎日です >>203 内部的に値で持つのでもポインタで持つのでもいいけど 「簡単に値として取り出せる」のはあまりよろしくないと思う。 これ (>>189 ) がおそらくファイルシステムを表現しようとするもの だという前提を考えたらオブジェクトの構造も ファイルシステムのモデルを抽象するものであるべきだと思うから。 ファイルはそれがある場所にも意味があるからファイルを象徴するオブジェクトが 場所から離れてやりとりされるのは違和感がある。 まあファイルシステムのモデルをどう捉えるかは私の感想でしかないから 何が妥当とは強くは主張しないけど、 いずれにしても実装上の都合じゃなくて使う側の感覚でどうなってて欲しいかという視点が要ると思う。 はちみつさん頭いいね アドバイスが丁寧かつ的確でいつも感心する ある構造体(集成体)Aについてconstexprでa1, a2, a3・・・といくつか作りました 別のクラスBのメンバ変数にconst A* m_ptrAがあってconstexprで作ったインスタンスのどれかを指すことにします この時Bのメンバ関数などで、 if(m_ptrA== &a1) という比較・条件分岐を行うのは意味のある比較になっているのでしょうか? 意味はある でもなるべくそういう判定は無しでいけるように設計したいところだよな Aクラスを作ってる意義が薄れる あと細かいこと言えばaddressofを使ったほうが汎用的というのはある c++のクソっぷりが如実に表れている関数 ありがとうございました 本当に列挙型代わりに使えるのなら面白いとも思いましたが まあ変なコードには間違いないですね 分岐の内容次第ではあるけど……Bが指しているAのオブジェクトごとに処理を切り替えるってのなら a1, a2, a3 …… がそれぞれ関数 (関数オブジェクト) を指す (所有する) ようにするのが常道ではあるね。 Bのメンバ関数の中では呼び出しを一文書くだけでいい。 分岐条件を網羅しそこなうしょうもないミスはよくあることだから 手作業での網羅を避けられるならそのほうがいい。 「The C Standard says that array indexes are (signed) integers. The reason behind that is that pointers and arrays are close in C. For example, tab[index] is strictly equivalent to *(tab + index). You can use pointer arithmetic with negative values, hence an array index can be negative」 とあるので、C 言語での配列添え字は符号付き整数 ですね。 しかし、C++ では、size_t とされ、符合なし整数 のようですが、矛盾しませんか? VC++の以下のマクロでは、 #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] eが偽の時にエラーになるようになっているようです。 これはつまり、 typedef char aaa[-1]; がエラーになる事を前提にしているようです。 しかし、もし、配列の最大要素数が、符合なし整数 であるならば、32BIT 環境の場合、 -1 は、0xffff_ffff と同じと言えば同じであるはずで、 コンパイラ内部で効率よく区別するのは難しいはずです。 どうしてるんでしょう。 何がいいたいかと言えば、32BIT環境だと 符号付き整数の最大値は、 0x7fff_ffff ですから、 char a[0x7fff_ffff]; は合法ですが、 char a[0xffff_ffff]; はエラーです。よって、 char a[-1]; はコンパイラは難しい処理をしなくても、 -1 は内部表現が 0xffff_ffff ですので そもそも範囲外の数値と見なせます。 ところが、もし、配列最大数が unsigned の領域まで許されるならば、要素数が 0xffff_ffff の配列も合法だということに なります。 ならば、要素数の[] の中に-1 を指定した 場合の処理は難しくなりそうだ、ということです。 なおそもそも、32BIT の Windows 環境 だと、ユーザーが使えるアドレス空間は 最大で 0x7fff_ffff 程度までですから、 バイト数的に確保は出来ませんが。 ならば、そもそも、C++がunsigned 型 であるところの、size_t を採用しているもの なかなか不可思議であります。 長いからよく読んでないけどコンパイラは型を認識をしてんだから-1と0xFFFFFFFFは区別してるだろ C++の配列添字はstd::ptrdiff_t(符号付き)です 配列を宣言するときの構文と添字演算子を使うときの構文を混同してない?前者はブラケットの中身が正じゃなきゃだめで後者は負でもいいってだけの話だと思うんだけど int main() { int hoge[-1]; // ここで負の値を指定することはできない hoge[-1]; // でもこれはいい (*((hoge)+(-1)) と解釈される) } せっかくだからC++23の仕様書も見てみたけど、§9.3.4.5の1には「配列のサイズはstd::size_t型(に変換された)定数式で、その値は0より大きくなければならない」って書いてあって、§7.6.1.2の2には添字は「スコープ無し列挙型か整数型」て書いてあったよ(該当箇所だけつまみ読みしたから正しく読めてる保証はできないけど) >>210 C の配列宣言子の角括弧内に書ける数値は 0 より大きい値に評価される整数定数式であることが条件で、具体的な型に規定はない。 式の型がなんらかの具体的な型に強制 (型変換) されたりはしないので signed int なら signed int だし、 unsigned int なら unsigned int のままだ。 VLA のときは定数式という条件は外れるけどそれ以外の制限はだいたい同じ。 C の添字演算子の場合もそう。 型は整数であればよい。 (値は制限の範囲内である必要はある。) どこで見た説明を根拠にしているのか知らんけど、その signed が括弧書きなのは signed 「でもよい」という意味だと思うよ。 std::functionって、有効な関数がセットがされているかどうかでブール値を返しますが、 一旦有効化した後にこれを無効化したい場合って、nullptrを代入したりしていいんでしょうか そしてその場合std::functionの中身はうまいこと解放されたりするんでしょうか 場合によってはラムダ式を使ってオブジェクトをキャプチャしていたりして あまりその辺りの説明が見当たらない感じがしました >>212 >長いからよく読んでないけどコンパイラは型 >を認識をしてんだから-1と0xFFFFFFFFは >区別してるだろ char a[100-101]; みたいに結果的に -1 になった場合は、 32BITコンパイラの場合、果たして内部で 0xffff_ffff と区別をつけているかどうか。 unsigned型と考えれば0xffff_ffffであり、 signed型と考えれば -1 です。 ターゲットが 32BIT Windows どちらもエラー になる可能性は高いですが、理由は結構異なる と言えば異なると思います。 もっと言えば、32BIT ターゲットで、 char a[0x80000000 | 1]; みたいな場合、中味は signed と 捉えれば「負数」ですが、unisgned と 捉えれば、0x80000001 という大きな値 に過ぎません。 どちらもエラーになる可能性が高いですが。 リテラルにも型がある 1はint 0x80000000はunsigned int 演算結果はunsigned int ルール決まってるから x86のアセンブラのディスプレースメントは符号付いてるけどな 他のマシン系はワカランけど >>222 32bit環境には64bit整数はないと思ってるの?? >>223 なるほど。そうなるわけですね。 本当に書いた人の意図がどうかに関わらず、 規則で決まっていると。 1UL のように書いてあれば unsigned。 そして、UL のようなものを書いてない場合、 1 のように小さな値は、signed ですが、signed の 範囲を越えるようなものは、unsigned になる、 などの規則があるわけですね。 >>185 >>183 の主張の >一方、例外を生じないライブラリの使い方(関数の呼び出し方)を心掛けるかどうか。これなら選択肢がある が完全に読み飛ばされている件について: 例外を生じないライブラリの使い方で設計したら、funcB()から例外が飛んでくるのはバグなので 調査と修正の対象になる。 (結果的にやっぱtry { funcB(); } catch (/*略*/) { ... } いるじゃーん?となる可能性はあるがたいていはそうはならない >>188 のように自分が何をやっているのか認識しないまませき止めるのは論外すぐる…… >>186 >catchしたらテストケースが増えるかどうかという話とはなんも関係がない。 あっる catchする必要性箇所を設計で厳選すればcatchが減るのだからテストケースは減らし得る 例外を使う場合: スルーしたりcatchして再スローが生じるfoo()の呼び出し箇所(とするのが現実的でないなら呼び出しパティーン)がm個、 スルーしたりcatchして再スローする段数が(簡単のためここでは平均とする)a個、 foo()が例外を生じるパティーンがn個なら、m^a^n個のテストケースが必要なところであるが catchする必要性箇所を設計で厳選した場合: foo()の呼び出し箇所(とするのが現実的でないなら呼び出しパティーン)がm個だとしたら、 例外が飛んでこないことを確認するのテストケースがm個のオーダーで要るだけ…… >>228 読み飛ばしてねえよ funcB()は処理を中断すべきエラーが発生する可能性があるんだろ?だったらそれを適切に処理して後続の処理をやったりやらなかったりする必要があるわけだろ? それはfuncB()がエラーを例外で返そうと戻り値で返そうとなんか他の方法で返そうと何も変わらないはずじゃないか >>229 >例外が飛んでこないことを確認するのテストケースがm個のオーダーで要るだけ…… いったい何をテストしようとしているんだろうか。 仮に「例外が飛んでこないことを確認するテスト」なるものができたとして、catchしたらそれができなくなるのか? 前半のよくわからない計算はcatch句を書いたらそのC0網羅のためのテストケースが必要になるとかいうことなんだろうか。 >>228 >>>188 のように自分が何をやっているのか認識しないまませき止めるのは論外すぐる…… どこが論外?>>169 でぜんぜん問題ないが。 >>232 それは未知の例外投げてきたライブラリを信用し過ぎ 製品ならそういう「たぶん大丈夫っしょw」的なのは許されないね >>233 逆だろ。catchしないのはライブらにが未知の例外を投げてこないだろうと信用してるってことだろ。 >>234 catchしないということは終了させるということ 見かけ上動き続けたらいいってもんじゃない >>232 それは未知の例外投げてきた原因を調査しなさすぎ 製品ならそういう「たぶん大丈夫っしょw」的なのは許されないね >>233 ドキュメント通りに例外発生条件にならないように呼んでやったのに 例外を飛ばしてくるライブラリって一体…… 製品やぞ…… 質問なのですが Q1. std::ldexp(0.0, 0.0) が0.0なのですがこれは 0^0 = 0という大胆な主張なのですが何で決まっているの? STLがIEEE735に従っているだけ? Q2. 最小の(絶対値が最小の正の)非正規化数は const auto min_expn = std::numeric_limits<double>::min_exponent; const auto digits = std::numeric_limits<double>::digits; として、std::ldexp(0.5, min_expn - digits + 1) で正しい? (実際 std::ldexp(0.5, min_expn - digits + 1) > 0.0 やが std::ldexp(0.5, min_expn - digits + 1) / 2.0 == 0.0 であっる Q3.にもかかわらず、 std::ldexp(0.5, min_expn - digits) > 0.0 になるのはなんで……orz 訂正 |||。n_ 誤1: IEEE735 正1: IEEE754 誤2: 非正規化数 正2: 非正規数 >>237 決まっていない。言語仕様としては未規定。 std::numeric_limits::is_iec559 が真であるならその挙動をあてにしていいがそうでないときは各環境の事情による。 >>236 あんたの認識じゃ catchする=見かけ上動き続ける なんだ? なんか根本的に勘違いしてる気がする。 例外は「関数外にエラー発生を伝える」ための「方法の一つ」でしかない 関数の処理がどんなエラーを発生させうるか、受け取った外側の処理がその情報をどう取り扱うべきかという問題とは完全に直交してる (言語ごとにある程度の慣例はあるけどあくまで慣例) 例外に変なこだわりや的外れな批判をしてる奴は大体そこを勘違いしてる アンカ間違えた、すまん >>241 は>>235 宛な。 >>242 お前はバグのないお花畑を考えてるからそういう理想的な抽象論を持ち出すんだよ c++の現実は道を踏み外したら即カオス stlのコンテナのpopに返り値がない理由は知ってるか? あのレベルの考察でソフトウェア設計している人間が世の中にどれだけいると思う? >>241 >>169 を否定している 知らない例外が飛んできた場合にcatchして握りつぶしてそのまま動作を継続するかどうかって話な >>244 バグのあるなしなんか関係ない設計の話だし、「例外はエラー伝達の具体的方法の一つ」って話のどこが抽象的なのかも分からないし、 「C++の現実」とか「カオス」が具体的に何のことで何の関係があるかも分からないし STLにpopがないのはnoexcept moveがない時代に例外安全に出来なかったからだけど今の話に何の関係があるかわからないし そんなのまともなC++erなら誰だって考えて設計してると思うけど、そうでないタコの話が何の関係あるかわからないし何もかも分からなすぎてすごい 仕事でそんなドキュメントやレビューコメント出すなよ >>245 知らない例外を握り潰すのも、知らない戻り値をガン無視するのも一緒 errnoが変わってるのを無視するのもint*err引数に渡した変数の値を無視するのもexpected<T,E>で帰ってきたEを無視するのも「知らんエラーを無視した」という結果は一緒 知らんエラーを無視していいかどうかの意味論と、そのエラーがどう伝播して来るかかは関係ない 関係ない話を混ぜるからお前のC++はカオスなんだよ >>245 ? そのtryブロックの処理が失敗したものとするって書いてあるじゃん。 >>231 >前半のよくわからない計算はcatch句を書いたらそのC0網羅のためのテストケースが必要になるとかいうことなんだろうか 例外が関数の階層をぶち抜いてfall-throughしてくることを忘れている発言 1. catchが書かれた関数が正しくcatchし、適切に処理するか(処理してせき止め or/and 必要な場合再スロー)(←要テスト! 2. fall-throughする関数が例外による処理の中断でおかしいことにならないか(←要テスト! 2をテストもせずに放置するとおかしくなる例は>>183 のとうーり これにより、例外を生じる関数foo()の呼び出しパティーンn個それぞれに対し、a個のテストが必要になっる 例外を発生させない使い方をするなら、n*a*mではなくmの定数倍(例外を飛ばさない使い方に依存擦る定数)。 例外が飛んで来たらバグ。わかりやすい 例外を多用しつつn*a*mをよくわからない計算とか言っている時点で以下略 >>244 以下の主張のどこが抽象論なのかkwsk、 1. ライブラリのドキュメントに従い、可能な限り例外を生じない使い方で設計する(>>236 2. 例外が生じない前提としたところは例外が生じないことをテストする(m個のオーダー)(>>229 3. 1と2の過程で意図に反して飛んでくる例外がある場合は原因を調査し、修正を試みる(>>228 例外が飛んで来たらバグ 4. 3を意図通りの形で解決できないことが判明した場合は (ライブラリの使用方法の当方の誤解、ライブラリのドキュメントの不備、ライブラリの作りの粗さによりこれはあり得る、 結果的にtry { } catch (/*省略*/) { ... }を付ける可能性もある(>>228 5. 例外を複数段fall-throughか再スローを許し、かつそれが起きた後もプログラムの 正常な動作の継続を意図する場合はテストケースが爆発する(>> 設計し、検証し、必要とあらばtry { } catch ( ) の追加も含めた修正を行うと言っているのやぞ;;; いっぽう藻前らの主張は 1. 例外をせき止めれば良い(←処理不能な未知の例外が飛んでくることが無いというライブラリに対する全幅の信頼 2. 例外を処理したりfall-throughしたり再スローしたりする関数はn*a*m個のテストしなくても動くっしょ (←自己のコードに対する無制限の気体 3. ドキュメントは100%信頼せず、読まない の3成分からなるわけやが…… >>248 >例外が関数の階層をぶち抜いてfall-throughしてくることを忘れている発言 やっぱり意味不明だな。catchすれば「階層をぶち抜いて」ってことはないわけだが。 >2. fall-throughする関数が例外による処理の中断でおかしいことにならないか(←要テスト! もしそのテストが必要なんだとすれば、catchしない場合はその例外が通過する 呼び出し階層全部でテストをしなきゃならないってことになるが。 >>249 >1. 例外をせき止めれば良い(←処理不能な未知の例外が飛んでくることが無いというライブラリに対する全幅の信頼 なるほどな。 catchする⇒無視する、握りつぶす って脳内変換されてんだな。 catch書いたからといって上に挙げられたようなテストができなくなるわけじゃないっしょ。必要と思うならやればいい。 3.の意図しない例外の原因調査なんて main() に例外が上がってきてプログラムが落ちてからより 発生個所に近い下層で catch できた方がはるかに調査しやすいと思うんだがな。感覚が違うなあ。 仕様書や規格書はその意図を正確に読み取ろうとするのに 掲示板の他人の書き込みは積極的に曲解しようとするのは何故か? 例外は糞!危険!意味不明!テスト漏れる!って言ってる奴ほど if (err != 0) { return -1; }が大好きなんだよな 本質的にやってること変わらないのに ファイル名に年月が使えないの困ります。 2024/02/11_データ.txt とか >>256 それ検索性最悪だから良くないんだよなぁ。 データ/2024/02/11/データ.txt データ.txt/2024/02/11/データ.txt あたりならまだ許せる。 スラッシュを使う習慣が悪いわけではないが プログラマの感覚だと ISO 8601 の方式に馴染みが有ることが多いってのはある。 年月日は「ふつう」がないのでみんなが苦労している 日本とアメリカとイギリスで順番が違うし 日本には「令和」とかあるし Windowsでも / をディレクトリ区切り文字として使えるけど(場面は限定的かもしれないけど)、その認識で使ってるのかな… Linux で * という名前のファイルを消そうとして うわあぁぁぁとなった話はたまに聞く。 使えたとしても使うべきでない文字もある。 262>> それ以外のファイルをすべて退避した上でディレクトリごと削除したことがあったな すみません、261ですが、Windows限定の話ではなかったですね 失礼しました… Linuxならi-nodeをしていすれば findと組み合わせてどんな名前のファイルも消去できるんだけどなあ windowsはなんか複雑だったような気がした iso8901にしない人はたぶんこの規格を知らないわけで意識低すぎだろと思ってしまう >>266 ISO 8901 は情報交換用 (要するに機械同士のやり取り) の時刻フォーマットを定める規格であって 言葉や文章で使うもの (人間が読み書きする目的) ではないと適用範囲の言及がある。 ファイル名はどちらの用途もありうるので >>256 がどのような状況を想定しているかによって ISO 8901 が適切かどうかは違う。 もし非技術者向けのシステムなら 文化固有の日付表現に対応できてないほうが意識低いという見方もある。 >>267 エンドユーザーの文化的背景に配慮したデータフォーマットの利点は、エンドユーザーの知識やメタファーを利用した学習曲線の低勾配化であって、技術的には負の遺産になりやすいことには注意が必要。 典型的には小組織から始まるURLの並びですな。木構造との相性がひどく悪い。 あるいは大きな桁から始まるバイト列とか。あんなの1桁目から始めればエンディアン問題とか無かった。 > 典型的には小組織から始まるURLの並びですな。木構造との相性がひどく悪い。 それは人間から見たときと機械から見たときの見やすさの違いでしかないような気がする でも日本の住所は大きい方から始まるんだよな アメリカは個人から始まる 文化の違いやけども、日本人は機械生命体だったのかもしれぬ enable_shared_from_thisなクラスで、shared_from_this()はコンストラクタの中では 呼べないようですね コンストラクタの中の処理でthisを渡したい処理があるのですが、どうしたら... そもそもそれ自体が間違っているのでしょうか コンストラクタが呼ばれる行の次でその処理を呼べばいいという説もありますが、 現在のコードがそれをやりにくい形になっていて >>250 >>2 . fall-throughする関数が例外による処理の中断でおかしいことにならないか(←要テスト! >もしそのテストが必要なんだとすれば、catchしない場合はその例外が通過する >呼び出し階層全部でテストをしなきゃならないってことになるが。 その通り。テスト不要としたいなら、例外が出た原因を調べて出ないようにするのが筋 原因を調査して対策せずに予防的にテスト不十分のtry { } catch () をてんこ盛りにする方がソフトウェアー品質が上がるという考えのはおかしい >>251 >catchする⇒無視する、握りつぶす って脳内変換 脳内変換ではなくて、予防的に入れたtry { } catch ()部分のテストが不十分な限り事実じゃーん? >>252 >本質的にやってること変わらないのに 別に。 return -1; は呼び出し側のバグで見落とすかもしれないが throw std::logic_error("*** ERR ***"); なら悪評千里を走ってバグの兆候が嫌でもワカル むしろ予防的なtry { } catch () が例外のメリットをreturn -1; に縮小してゐる >>253 藻前が二の句をつげないのは藻前の見識と資質の問題であって 漏れの責任ではないのでお間違えなきよう、 なのですよ…… テストって想定した動作環境、データ入力に対して想定した動作をするか確認をするわけで 想定しえないエラーや割り込みに対してはテストのしようがないんだけどな そのための例外処理だろ 例外が上がってくるってことはどこかで例外を投げてるってことだぞ。 問題が起きたところでその問題に対して例外を投げるという対処をしてる箇所がある。 想定してないなら例外送出すらできないよ。 その上で人間は大きいプログラムの全体を把握することは困難だし 機械的なチェックがしづらいという現実はあるって話だ。 アプリケーションを作っているのとOSを作っている人は別 それと同様に利用するライブラリがどのような例外を投げてくるか、もしくはそのライブラリがさらに下位のライブラリから投げられた例外をどう処理しているか アプリケーション開発者はそれらすべて想定できているとでも? ハードウェアやシステム含めて全部ひとりで作り上げる(もしくは密に情報共有できている)ならお前の言う通りだけどな >>276 「把握することは困難」という現実の話もしてる。 想定してはいて、しかしそれが伝わってない。 コミュニケーションの問題、自動化の問題として捉えるべき。 俺も、(もしくは密に情報共有できている)なら、と言う話をしているがな ただ「現実の話」と言うならば、伝わっていないことをコミュニケーションの問題、自動化の問題と言うのはナンセンスだわな お前自身がこう言っている > その上で人間は大きいプログラムの全体を把握することは困難だし > 機械的なチェックがしづらいという現実はあるって話だ。 ではWindowsと言う巨大プログラムにおいてMSの中の人はどの程度全体を把握していて、発生しうる例外を公開しているのか アプリケーション開発者はその公開情報をもとに *想定し* プログラムを組まなくてはならない さてアプリケーション開発者はOSなど下位のモジュールから飛んでくる例外をすべて想定できるのか? そもそも致命的な例外でアプリケーション自身の継続が困難な場合を除いて どんな例外でもあっても継続的な処理を可能にするのが例外処理だろうに (ここで言う継続的な処理とは問題なしとして先に進むだけでなく、異常があったとして正常な(処理の)出発点に戻るという意味でもある) 起こりえる例外をすべて想定せずともプログラムを安全に継続するための仕組みが例外処理だろ C++ の設計理念としては「そうは言っても現実はこうなっとるやろが!」という 状況に対処する方法があることも大事にしてはいる。 たとえ綺麗な方法ではなくても。 どのような問題が起こりうるのか (それなりには) きちんと想定するのは当然の大前提で、 それでもこれからリリースするソフトウェアに何が起こるかわからんのは仕方がないという話であって、 想定が不十分でも構わないという話でもない。 よくは無いが悪いときでもなんとかなるという程度の仕組みだよ。 >>271 一番いいのはコンストラクタの中でthisを渡す部分を何とかすることだけど、それが必ずしも間違ってるかは分からないので コンストラクタの中だけでその処理が呼ばれるなら生のthisを渡すことを許容しつつ、その処理の呼び出し可能範囲を限定するか そのクラスの構築をファクトリ関数経由に限定して、ファクトリ関数の中に構築とその処理呼び出しをまとめてしまうとか > 想定が不十分でも構わないという話でもない。 誰もそれで構わないとは言っていないので それでも起きてしまうエラーや割り込みに対応するための仕組みが例外処理だろ 身も蓋もない言い方をするなら そもそも想定できているなら事前に排除するだけで済むわけで例外処理の必要もない (もちろん分かっていても事前に排除せず意図的に例外処理に丸投げすることもあるのは知っている) アプリケーション開発者にとってもっとも想定できない問題ってのは実行環境に起因するもの >>272 >原因を調査して対策せずに予防的にテスト不十分のtry { } catch () をてんこ盛りにする方がソフトウェアー品質が上がるという考えのはおかしい 相変わらずずれてるな。 catch する == 原因を調査しない じゃないわけ。 >return -1; は呼び出し側のバグで見落とすかもしれないが >throw std::logic_error("*** ERR ***"); なら悪評千里を走ってバグの兆候が嫌でもワカル 戻り値のチェック漏れは静的局所的にチェックできるが例外は出てみなけりゃ結局澪とされるわけだが。 リリース後にユーザーサイドでその見落とされていた例外が発生してプログラムが落ちたりしたらそれはただのバグ。 read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる