C++相談室 part138
■ このスレッドは過去ログ倉庫に格納されています
次スレを立てる時は本文の1行目に以下を追加して下さい。 !extend:on:vvvvv:1000:512 C++に関する質問やら話題やらはこちらへどうぞ。 ただし質問の前にはFAQに一通り目を通してください。 IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。 前スレ C++相談室 part137 http://mevius.5ch.net/test/read.cgi/tech/1531558382/ このスレもよろしくね。 【初心者歓迎】C/C++室 Ver.103【環境依存OK】 http://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 STLつかうと一気に実行ファイルサイズが10倍に?! 環境によるだろ。 俺はBorland-C++5.6.2に -D_RTLDLL オプションを指定して、極力 ランタイムを使用するようにして使っているが、例えばstd::vectorを 使っても使わない時と比べ10Kほどしか増えない すげえ。ダイナミックリンクしといてファイルサイズが増えないとかいってるよ。この人。 C1010: プリコンパイル済みヘッダーの検索中に予期しない EOF を検出しました。 とかいうエラーが出るんだけどこれってどうすればいいの? #include <stdafx.h> 後死ね。 言葉が悪いな。それで教えているつもりか。 まぁヒントぐらいにはなったな。 うむごくろう。 ---- テンプレ ここまで ---- rad c++ builderでファイルの入出力やドラッグ&ドロップ 簡単なdb操作は出来る様になったけど、もう一歩踏み出したいです 福岡当たりで勉強会みたいなのはないでしょうか? 大阪、東京でも有るなら飛行機使っていきたいです 6です c++ builderのスレッドが合ったので そちらで聞いてみます 失礼しました >>6 「C++ の勉強会」 なんだか魅惑的な響きですね… 関数内にstaticつけたクラス変数定義した場合、 コンストラクタは関数を最初に呼び出したときだけ呼ばれると思います。 これはどういう仕掛けなのですか?どこかにフラグがこっそり用意されるのでしょうか。 >10 ちょっと書き方間違えました。 定義ではなく宣言です。 間違ってますでしょうか?ではコンストラクタが呼ばれるタイミングはどこでしょうか >>9 クラス変数とは言わないよ そのとおりフラグがある さらに11か14かは忘れたけどmt safeにもなった つまり同期プリミティブも裏で作られている >>9 コードで書いた方がいい。 どうせ用語を間違っていて、正確には通じてないから。 エスパーで話すのもありだとは思うけど、回答を信頼出来ないだろ。 virtualなデストラクタを持たないクラスを継承しているクラスを派生していない状態でコンテナ等に入れた場合、 エラーまたは警告にする方法ってある? 典型的な「デストラクタをvirtualにしろ」のケースであり、 安全性だけを取るのならそうすれば済むのだが、大量使用したいのでコストを限界までケチりたい。 可能であればコンパイラにチェックさせたい。 具体的に言うと、Matz曰く「実装が漏れてる」の典型的なケース、配列について、 長さと先頭のポインタをstructにして、各操作をそれに対するメソッドとして記述し、 スクリプト言語風に簡潔に書けるか試したい。 std::spanの再実装に近いので、そちらで言うと、 https://github.com/tcbrindle/span/blob/master/include/tcb/span.hpp std::spanを継承して各種メソッドを生やし、(クラスM) さらにそれを継承して以下3つのコンストラクタを持たせる。 クラスA. 型と既存ポインタと長さからの生成 クラスB. 型と長さを与え、allocaでの生成 クラスC. 型と長さを与え、heap上への生成 A,Bは問題ないが、Cはデストラクタでdeleteをする必要がある。 ここでstd::spanのデストラクタはvirtualではないので、(上記実装例の場合) vector<C>をvector<M>等と間違えたら不味い。 このときに、警告またはエラーを発生させたい。 もう一つよろしく。 C++でkey/valueソートしたい場合は ・std::unordered_multimap等にコピーしてからstd::sort ・自前で<key,value>を含んだ構造体を用意し、それに < を定義して、コピーしてstd::sort のどちらかって感じ? ちょっとまどろっこしいので、もう少し簡単な方法無いかな? doubleの配列をソートした際、何番目がどこに行ったか追跡したい。 .NETだと Array::sort(array0, array1) があり、 array0 に double の配列、 array1 に [0 ... N-1] な配列を指定しておけば、array1の結果で簡単に追跡出来た。 記法が原始的ではあるが、結果的にはこっちの方が楽で良かった。 std::sortで2つの配列を取る物があれば助かるのだが、なさそうだし。 boostも見たが、よく分からん。 抽象型のメソッドを使ったときにも型を失わず、派生型のままで返す方法って無いよね? 継承を使わず、テンプレートで展開するしかないか? コード上で展開されるのが、多少勿体ないんだが。 >>14 の実装で、 各種メソッドをクラスMに突っ込み、それを継承していると、 Cからメソッドを呼び出した際、どうしてもM&等の型しか返せず、 ダウンキャストがいちいち必要なのがウザイ。 具体的には、fromは既存の配列からコピー、sortはソートするメソッドとして、メソッドチェーンで初期化する際、 C& test = (C&)C( ... ).from( ... ).sort(); となり、fromやsortがM&を返すのでC&にダウンキャストする必要がある。 従来方式の初期化して使用なら問題はない。 コンストラクタは派生型を返し、メソッド群はM&で閉じているので。 A& test = A( ... ); test.from( ... ).sort(); メソッドをvirtualにすれば回避出来るはずだが、無駄にvirtualにしたくない。 B/C共に全く同一の関数で済むはずなので、可能で有れば共有したい。 諦めてB/C毎に同じ関数をtemplateで展開すれば出来るのは分かるが、これはしたくない。 何か方法有る? そもそもなんのためにMから継承してんのか考えてみたら >>17 オブジェクト指向ではMで閉じるというのが正しいと思いこんでるんだろ。 それは一面にすぎない。 JavaScriptではメソッドチェーンで型を失わない。 だから上記のようなことも平気で出来る。 勿論C++でも実装を別々にすれば出来るが、ダブる分無駄に膨らむ。 或いはvirtualにしても出来るが、これはポインタ一つ分データが膨らみ、呼び出しも遅くなる。 最適化した状態での記述方法がない。 今回、AとCの違いはデストラクタ内で解放するかどうかだけであり、 当然全てのメソッドは共有出来る。 順当なら継承が妥当だが、virtualにしないと型を失ってしまう。 (この点、全てvirtualであるJavaはオブジェクト指向原理主義としては筋が通っている) ちなみに技術的には、super に対するキーワード derived が足りないのだと思う。 クラスM内で、 M& from(){ ... ; return *this;} ではなく derived& from(){ ... ; return *this;} と出来て「呼び出した型」を返せれば全く問題ないんだが。 この辺のキーワードって無いよね? なんだ、JavaScriptという一側面だけ見てC++に立ち向かってるアホだったのか まぁがんばれよ C++がメソッドチェーンに向いてないのは確かだよ。 それ向けの文法も用意されてない。 多分「継承」に対して型を失うこと自体が間違いなんだよ。 C++はそこら辺が古い。 ただ、ダブって良ければtemplateで解決出来るのも確かだが。 JavaScriptの場合は型が失われないんじゃなくて「無い」んだな。 レシーバの型に関係なく呼び出せてしまうだけ。 >>20 あとついでに言うと、その選民思想はマジで止めろ。 C++だけの話でもないが。 というより最近「俺がやってる言語スゲー」な奴が多いのは何でだ? 一昔前は全員Cが出来、その上で他言語だったから、その手の争いは皆無だった。 それ以前にプログラミングがきちんと出来れば、後は文法だけの問題だから、 多言語化は容易だし、実際全く問題ない。 「俺の言語スゲー」でイキれる奴って文法しか見えない馬鹿のような気がするが。 C++はコンパイラ向けの文法ばかり多くて、本質的なプログラミング用の文法は多くない。 今回も、JavaScriptだと容易に実現出来るのに、C++だと記述出来ないだろ。 あまり他言語を馬鹿にしていると足をすくわれるぞ。 CRTP使えばどうだろう? template <typename Derived> class M { public: Derived &from(){ return static_cast<Derived &>(*this); } }; class A : public M<A>{}; class B : public M<B>{}; >>22 まあその通りだが、 C++: 記述出来ない JavaScript: 動的型なのでそのまま書けるし、動作する Java: 全部virtualだからそのまま書ける(ただし、これでいいのならC++でも書ける) Go: 継承を廃止してしまったからそもそもこの問題は発生しない? Rust: ちょっと見たがよく分からん まあ俺はやっぱり、「継承」で親の関数を呼んだら型が失われるのは間違いだと思うよ。 仮に Z : Y : X と継承していたとして、 (Zの実体).(Xのメソッド).(Yのメソッド) とは出来ないでしょ。(Xのメソッドの時点でX&になるから) これはメソッドチェーンする気なら使いにくい。 (これまでは居なかったから問題にならなかっただけ。バラバラに書けば出来るので) >>24 とりあえず今はそれで実装してる。 それが16で言ってる > 諦めてB/C毎に同じ関数をtemplateで展開すれば出来る というやつ。 ただどう見ても無駄なので、可能で有れば実体も一つにしたい。 >>26 > ただどう見ても無駄なので、 どのへんが無駄なのか教えてほしい >>27 テンプレートは型毎に展開されるし、自明では? むしろ通じない方が不思議だ。 仮に俺が言ったように19の表記が出来れば、 オブジェクトコードはその部分は半分で済むし、命令キャッシュのヒット率も上がる。 勿論C++でもvirtualにすればこれらの点は解決するが、 呼び出しが遅くなってデータオブジェクトもポインタ一つ分膨らむだろ。 今のC++では最適化したオブジェクトコードを吐かせる記述が出来ない。 C++コンパイラの気持ちになって考えてみなよ お前の望みは無理だから どうせベンチとらずに遅いとか言ってんだろ だまってvirtual使うかダウンキャストするかそもそも継承使わないかどれかにしとけ >>29 ベンチ取らなくても自明だろ。 そしてC流の「手動」オブジェクト指向なら、自分で関数を手動で切り替えるのだから、実現出来るんだよ。 ただ、現実的には、derived等のキーワードが出来ればC++でも普通に可能だぞ。 単一継承ではthisの値は型によらず同じだし、 この場合に親のメソッドを使ったら親の型になるというのは、 純粋に「コンパイラがエラーを検出するだけ」の為であり、実装には何ら影響がない。 だからコンパイラがエラー検出さえしなければ通るし、そのまま動作するコードになる。 C++は過剰にエラーを検出しているだけなんだよ。 なお、やっぱ継承じゃないと使いにくいわ。 A/B/Cってのはコンストラクタ/デストラクタだけの違いだから、 他から呼び出すときは型Mにして多態したいのだが、 CRTPだとこれが出来ないorz 必要なのは「ダウンキャストの型推論」か? 文法的に見てダウンキャストが安全な場所はあるだろ。例えば、25の > 仮に Z : Y : X と継承していたとして、 > (Zの実体).(Xのメソッド).(Yのメソッド) とか。 X& → Y&のダウンキャストも自動アップキャストと同様出来てもおかしくないし、これが有れば解決だ。 「ダウンキャストは悪」って事で止まってしまってるだろ。 もっとも、全部virtualで単一継承ならダウンキャストはほぼ要らないのも事実だが。 自己修正。 >>28 > 今のC++では最適化したオブジェクトコードを吐かせる記述が出来ない。 これは間違いだった。 いちいちダウンキャストすれば(ソースはうざくなるが)最適なオブジェクトコードが出る。 ダウンキャスト忘れはSyntaxErrorだし、妥協するならこっちかも。 Mを継承してるのが間違い Mは実装を共通化してるだけだろ Mをコンポジションにしてデリゲート C++ならprivate継承にしてデリゲートはテンプレートにすりゃいい >>35 それで何が嬉しいんだ? 記述も無駄に増えるし、何もメリット無いように思うが。 (Mへのデリゲートの部分が余分に必要) どうせ委譲部分を全部書く気なら、 コンポジションせずに単に自前で戻り値をダウンキャストした方がいいと思うが。 例: Class C : M { C& from( ... ){ return (C&)((M*)this)->from( ... ); } }; コンポジションにすると上記のアップキャスト部分(M*)が必要なくなるが、 その分無駄にポインタ一つ分データが膨らむだろ。 上記のダウンキャスト/アップキャストは実行コード上には現れないのだし、 2段呼び出しを省いてくれる最適化がかかるのなら、 呼び出し側でダウンキャストする必要が無い為、まあまあ。 (ただしfromの実体と委譲でクラス側のソースコードは増えるが) ちなみに単純な実装なら 「呼び出し側でダウンキャスト必須」になってウザイのだが、 C++的にはこれが正しいような気がしてきた。 俺にはこれは「過剰な型チェック」にしか見えないが、C++はそういう言語でもある。 コンパイラのチェックから逃れる為にデータ構造を変更するのは本末転倒だし。 ダウンキャスト撲滅教の信者は、次から ・derived等、継承で親のメソッドを使ったときにも「呼び出し側の型」を返す為のキーワードの整備 ・ダウンキャストの型推論 のどっちかをプッシュしておいてくれ。 傍から見ていると、メソッドチェーン自体なにが嬉しいんだろう、と思ってしまう。 >>38-40 そりゃ君らが老害だからだよ。 老害ってのは肉体的な年齢のことではない。 好奇心/興味を失った結果、新しい価値観を認めないから老害となる。 新しい言語を見てみろ。全てメソッドチェーン出来るだろ。 最初は戸惑うかもしれないが、慣れれば相当便利なんだよ。簡単に凝集度を上げていける。 もう1行に1個ずつ処理を書いていていい時代じゃなくなりつつあるのさ。 とはいえ、クラスも当初は無駄だと言われていたのだろうし、今ならラムダやLINQが該当するのだろうけど。 thisポインタ返すメソッドチェーンってクソだろw perl脳と同じ おかしな主張を生暖かく見守っていたのに、そんなストレートな御意見を さて、続き。 C++で『デストラクタありの』オブジェクトを返すとき、お前らどうしてる? α: しない。上位関数でオブジェクトポインタを渡して上書き。(Cスタイル) β: スマポで渡す。(スマポ教)(=CLIスタイル) γ: reinterpret_cast。 ← とりあえず今の実装 Δ: 他に何かある? 非常に当たり前だが、 戻り値として一時オブジェクトを用意すると、それのデストラクタが実行されてしまうことに気づいた。 (今更なのだが、これまではVC++/CLIでCまたはCLI(managed)スタイルで書いていて、 C++(unmanagedまたはネイティブ)スタイルはほぼ使っていなかったから気づかなかった) これでは困ったことに、関数呼び出しで初期化がやりにくい。 具体的に、駄目なコードは以下。 template<typename T> struct M { // メソッド群 T* ptr; int length; T& operator[](int idx){return ptr[idx];} M(int length, T* ptr) : length(length), ptr(ptr){} M& from( ... ){ ... ; return *this;} M& sort(){ ... ; return *this;} // M& alloc(int length){ ... ; return *this;} // --- (α) // M(int length) : length(length), ptr((T*)malloc(sizeof(T)*length)) {} // --- (γ) }; template<typename T> struct C : M<T> { C(int length) : M(length, (T*)malloc(sizeof(T)*length)) {} // heap上に確保 ~C(){free(this->ptr);} }; C<double> calc_result_vals( ... ){ // --- (γ) calc_result( ... ); // in-placeで結果が計算される。 return (C<double>&)C<double>( ... ).from( ... ).sort(); // 結果をコピーしてソートして返す } // <----ここでCのデストラクタが実行される void test(int num){ MyContainer<C<double>> vals(num); // アロケーションのみ --- (β) for (int i=0;i<num;i++) vals[i] = calc_result_vals( ... ); // 初期化 --- (α)(γ) } 内容はこれまで通りだが、再度説明する。 Mはメソッド群を持つベースクラスであり、メンバ変数はポインタと長さのみ。 つまりshared_ptrと同様のヘッダであり、データは別区画にある。 Cのコンストラクタでデータエリアをheap上に確保する。 testではコンテナを用意し、各インスタンスを calc_resut_vals() によって初期化する。 Cはヘッダなのでコピーでいい。(32bit環境なら8Bytes) というノリだったのだが、GC言語ではこれでいいが、C++では前述の通り動かない。 calc_result_vals 終了後に戻り値Cのデストラクタが実行され、データエリアが開放されてしまうからだ。 (ヘッダ自体はコピーされるが、中身が無効アドレスを指した状態になる) このとき、お前らどうしてる? まず思いつくのはCスタイル(α)だ。 test内の初期化を、戻り値ではなくポインタで渡し、子関数で上書きさせる。 for (int i=0;i<num;i++) calc_result_vals(&vals[i], ... ); // --- (α) しかしやっぱ代入形式で書きたいのと、 一時オブジェクトを作らない為には、 Containerでmallocではなく各インスタンスをnewして空として初期化し、(ここまではまあいいが) そこに上書きでポインタを初期化するというおかしな操作(allocメソッド)が必要となる。 これが流れ的にイマイチ。 スマポ教団なら全てスマポで対応しろ、か?つまりtest内のコンテナを MyContainer<shared_ptr<C<double>>> vals(num); // --- (β) とし、calc_result_valsはshared_ptrを返すというもの。 しかしこれは無駄にスマポを介している分ウザイし、速度も遅い。 とはいえ型には矛盾が無く、フローとしては綺麗ではある。 (GC言語は実質的に全てこれ) 型なんて飾りですよ、なら、MにC同様のmallocするコンストラクタを用意し、 calc_result_vals上で作る一時オブジェクトはCではなくMとし、(デストラクタが空) 代入時にキャストして強引に突っ込む、とも出来る。 M/Cの区別は「heap上に新規作成するか」ではなく、「寿命を管理するか」に変わる。 M<double> calc_result_vals( ... ){ calc_result( ... ); return M<double>( ... ).from( ... ).sort(); // Mを一時的に作り、Mを返す } // デストラクタは空なのでheapは解放されない for (int i=0;i<num;i++) *(M*)&vals[i] = calc_result_vals( ... ); // キャストして強引に突っ込む(γ) 代入形式で書けるし、最速コードはこれだが、強引過ぎか? ただC++でこれやったら最適化によっては死んだような… お前らどうしてるよ? 他の方法(Δ)が有れば是非。 なお、「Cを継承したDを作り、Dのコンストラクタ内でcalc_result_valsを呼んで初期化」は 無意味に結合が増えそうなので却下。 >>41 関数型言語で使われるパイプラインとの区別もついてないんだろうねぇ。 mutableなオブジェクトに対して連続的に操作を行う際にレシーバの記述を 省略できるというだけでしかないのに。 >>48 意味不明。そもそも俺は「パイプライン」知らんし。 以下見る限り、データをメソッドで処理するのではなく、 データをメソッド配列(メソッド関数ポインタ配列)にくぐらせる感じか? > https://postd.cc/an-introduction-to-functional-programming/ しかし今回は演算結果をコピーしてソートして返すだけだから、どっちでも変わらん気もするが。 callが使えればパイプラインも生きるのかもしれんが。 α':参照渡し Δ:move (デストラクタは動くけどコストは低くなる) >>50-51 おおサンクス。ムーブ忘れてたわ。 つっても俺の今の環境(VC++2008)だと出来ないっぽいが、この場合は正しくはムーブだろうね。 class C : public Mのときに c.chain().chain.chain()で戻り値がCの型のオブジェクト指向の静的型付き言語を知らないんだけどあるの? 少なくともc++、c#、java、kotlin、swiftはできない ダウンキャスト推論しろとかね タイプセーフを何だと思ってんでしょ 一応報告。 色々調べた結果、placement new を使えばαの時の「未初期化のthisを使う」気持ち悪さは無くなることが分かった。 これとムーブを比べると、以下。 Cスタイル(α): × 代入形式で書けない。 ◎ 最初から最速コードが出る。(costructのみ) ムーブ:(俺の環境では) ◎ 代入形式で書ける。 △ダウンキャストを書く必要がある。 × return (C<double>&)C<double>( ... ).from( ... ).sort();だと全く最適化されず、 construct/copy/destruct/move/destructとなる。 △ C<double> retval(pat->num); retval.from((double*)pat->result).sort(); return retval; とベタに切ると、 NRVOが一つだけかかり、construct/move/destruct となる。 (opereator=のオーバーロードが最適化に影響しているかも試したが、関係なかった) いまいちソースは美しくないが、速ければいいだけならCなのはいつも通り。 (NRVOの最適化済みソースを手動で書くのだから当然) ムーブにするか、いっそのこと代入/コピー禁止でunique_ptrの機能も持たせるか考え中。 コンテナを自作しようとしているのだが、デストラクタの書き方が分からない。 教えてもらえないだろうか。 (自信は持てないが) 俺の理解では、コンテナのデストラクタは中身のデストラクタをキックする必要があって、 今は以下のように書いていて、それなりに動いているように見える。 ~MyContainer(){ for (int i=0;i<length;i++) ptr[i].~T(); } 要するに中身のデストラクタを一つずつ直接呼び出している。 ところが、例えばGNUのvectorのデストラクタは空だ。 > 00126 ~vector() { } > https://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/api/a01115_source.html これはどういう事なのだろうか? 他に参考になるソースでもいいから教えてもらえれば助かる。 なお、以下では俺と似たようなことをやっている。 > ~Stack () throw() > { > std::for_each(array_, array_ + top_, destroy<T>); > ::operator delete(array_); // グローバルスコープの delete 演算子 > } > https://ja.wikibooks.org/wiki/More_C%2B%2B_Idioms/%E6%B1%8E%E7%94%A8%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E4%BD%9C%E6%88%90%E7%94%A8%E3%82%A4%E3%83%87%E3%82%A3%E3%82%AA%E3%83%A0 (Generic_Container_Idioms) >>57 vectorは所持するアロケータがメモリの管理をすべてやっているから vector自身のデストラクタでは特にすることがない >>58 なるほど。 ではそのアロケータのdeallocateメンバ関数は誰がキックするんだ? 俺はそれが vector のデストラクタに書かれているのかと思っていたんだが。 以下参考。 > C++11では、std::allocator_traitsというアロケータアクセスの中間インタフェースが用意されたおかげで、 > 自作アロケータに必要な実装がだいぶ減りました。 > > 自作アロケータに必要な最小コードは、以下のようになります。 > > 要素型value_type > 特殊関数(デフォルトコンストラクタ、コピーコンストラクタ、ムーブコンストラクタ) > 別な要素型のアロケータを受け取るコンストラクタ > allocate()メンバ関数。(hintパラメータはあってもなくてもいい) > deallocate()メンバ関数 > operator==とoperator!= > https://faithandbrave.hateblo.jp/entry/2014/02/14/160506 >>60 vector内部にallocatorを持っている場合、 allocatorのデストラクタはvectorのデストラクタが呼び出してやらないと連鎖しなくね? なお、以下ではやはり自分のデストラクタででfreeを呼び出し、その中でalloc.deallocateされてる。 > StrVec::~StrVec() { free(); } > https://books.google.co.jp/books?id=P1D5DAAAQBAJ& ;pg=PT746&lpg=PT746&dq=deallocate+%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97&source=bl&ots=1rmEQsOAY0&sig= NRKyLHuLVtPQK5Yb2Nk_YU_pTNs&hl=en&sa=X&ved=2ahUKEwjCwe_q3sTdAhUNQd4KHc2FDi0Q6AEwA3oECAcQAQ#v=onepage&q=deallocate%20%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97&f=false いろいろと間違ってる > for (int i=0;i<length;i++) ptr[i].~T(); > 要するに中身のデストラクタを一つずつ直接呼び出している。 こんなことする必要ない デストラクタはインスタンスが消滅するまえに自動的に呼ばれる ↓コレはdebug用 みるソースが適切じゃない > https://gcc.gnu.org/onlinedocs/gcc-4.6.3/libstdc++/api/a01115_source.html 00078 #ifdef _GLIBCXX_DEBUG 00079 # include <debug/vector> ← コレをみてる 00080 #endif ↓こっちみなさい https://gcc.gnu.org/onlinedocs/libstdc%2B%2B/libstdc%2B%2B-html-USERS-3.4/stl__vector_8h-source.html 00268 ~vector() 00269 { std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish); } >>62 おおサンクス。見るソースを間違えていたか。 なお俺が作ろうとしているのは「コンテナ」な。 だからデストラクタの連鎖の開始をキックする必要がある。 そのソースでもされてるだろ。 × デストラクタの連鎖の開始をキック ○ デストラクタの連鎖をキープ 開始のキックはコンパイラによってされるが、連鎖は手動でキープしてやらないと次に続かない。 コンテナの場合はこれが必要なはず。 newはどうしてるんだい? placement new? それなら自分でデストラクタ呼ぶので正解 普通のnewなら、普通にdelete >>65 ああ、目の付け所はそこで合ってる。 先に言っておこうかとも思ったが、話が無駄にずれるので止めておいた。 わざわざコンテナを作ったのは、コンテナ領域をallocaで確保したかったから。 そこに結果的に placement new して、ヒープ領域にデータ領域を持ったオブジェクトを配置してる。 だからそれらを解放してくれないと不味い。 そのデストラクタをコンテナのデストラクタからキックしている。 (というか、これをやらせる為に簡易コンテナにした。 単にallocaで可変長配列を確保してその中に入れただけでは、 デストラクタを起動するコードが『自前で、上位側に』必要であり、これがC++の思想と反するから) 要するに alloca をもっと使ってみようというテストなのだが、 「コンストラクタで領域を確保出来ない」(関数呼び出しでは初期化出来ない)のが地味に使えない。 C++は何故か forceinline までも「無視していい」という仕様にしているようだし。 (inlineは無視してもよく、forceinlineは無視しては駄目、という仕様に普通はするだろ) ただ、自作アロケータを既存のコンテナにはめ込めるのなら、その方がいい。 この解があるなら alloca がいらない子扱いなのも道理だ。 >>37 >・derived等、継承で親のメソッドを使ったときにも「呼び出し側の型」を返す為のキーワードの整備 合ってるかどうかわからんけど、共変の戻り値じゃあかんのけ? >>66 コンテナが可変長でスタック上にplacement newで置く 中身は普通にヒープなの? 不思議なもん作ってんのなw それなら中身はコンテナのデストラクタでdeleteするだけじゃん >>67 駄目だな。 仮想関数にしないといけないのと、 それは子が子のままでいられるだけであって、子が親のメソッドを使った後も子で居続けられるわけでない。 > 実際に取得する型が親クラスに引っ張られないメリットを享受できる > 自分自身の型を返す関数を定義する時など、親クラス固定だと、受け取った側でのキャストが面倒ですしね。 > http://cpp.aquariuscode.com/covariant-type やはり既知の問題ではないか。 (C++しか使ったことがないなら意味が分からないと思うが) JavaScriptの場合はクラス階層とインスタンス階層が分離しており、 各インスタンスはクラス階層を派生させてを作る。 だから元々親階層のメソッドから子階層のメンバ変数を参照出来るし、それがデフォの使い方だ。 クラス階層とインスタンス階層は文法的には違いが無く、クラスも継承出来るが、インスタンスも継承出来る。 これを上手く使えば、メモリを大幅に節約することが出来る。 C++にはこの記述能力がない。 理由はクラスとインスタンスが明確に分離しているからだ。 JavaScriptの挙動をC++用語で言えば、 thisが常に仮想thisであり、メンバ変数は全部仮想メンバ変数となっている。 だから親のメソッドを使っても派生型のままであり続け、自由にメソッドチェーンが出来る。 ただしここら辺はやや宗教的でもある。 親クラスの関数が派生クラスの変数を操作することを「仮想this」で実現するなら、 型安全ではなくなってしまう。 ただし実装は、単一継承の時には単に型チェックを外すだけと、極めて簡単であり、やる気だけの問題だ。 (ただしC++の場合には多重継承があるので若干問題がある) なお、型安全を取りたいなら、仮想thisではなく、仮想メンバ変数で実現する事になる。 こちらはC++でも問題はない。(ただし動作速度が遅くなるが) >>68 当初は delete &ptr[i]; と記述していたのだが、これは 1. ptr[i].~T(); (各エレメントのデストラクタのキック) 2. free(ptr[i]); (メモリ区画の解放) の2つを実行するらしくて、駄目だった。 今の各エレメントはallocaで確保した区画に placement new しているので。 > 不思議なもん作ってんのなw 今回は事前に全部計算してalloca出来るが、 コンテナ長だけ親で確定、中身の長さは子でしか確定出来ないことも普通にあるだろ。 例えば、LGBT共のおかげでFacebookには56種類の性別があるらしいが、 これに対して、無作為に10,000人の性別を調査するとして、 コンテナ長は56で親で決まるが、 各性別人リスト長は子関数で調査しないと決まらないだろ。そこをheapに取ってる。 勿論、親も含めてheapに取り、ジャグvectorとするのがC++流であり、だからC比でいちいち遅くなる。 そこら辺を改善出来ないかのテストだ。 ああ、いつぞやのJS厨か・・・相手にするんじゃなかった >>70 何を悩んでんのかよくわからんが 普通にヒープから取ったんならdeleteだし スタックをplacement newしたんなら自分でデストラクタ それだけの話 というかね、はっきり言ってでかいデータをスタックに置く発想がセンスないぞ アホやな スタック関係ない アホは連続した一枚の板みたいなヒープに ポインタの列ではなくオブジェクトインスタンスのメモリイメージの列をシリアルに並べてる ホントな、アホしかいいないわ 俺JavaScriptもやってるけどこいつの言ってることはよくわからんよ たとえば64byteのメモリが必要なクラスがあったとする アホが作ったコンテナでは例えば要素が5個なら こんな感じになるとアホはいってるワケ [0][64byte] [1][64byte] [2][64byte] [3][64byte] [4][64byte] メモリの板に64*5のメモリイメージが配置される 要素が1つ増えるたびに64byte必要になることになる ポインタなら(仮に32bitなら)こうなる [0][4byte] ← [64byte] [1][4byte] ← [64byte] [2][4byte] ← [64byte] [3][4byte] ← [64byte] [4][4byte] ← [64byte] メモリの板に4*5のメモリイメージが配置される さらに64byteのバラバラのメモリが5個できる つまりメモリフラグメンテーションがおきることになる >>69 そんな長々とオレオレ理解をオレオレ用語で説明されても困るわw スタックで、とかメソッドチェーンで、とかにこだわりすぎだよ 言語に合わせてサクッと作れ そもそもスタックとかいってるオマエも 相当頭悪いという自覚が必要 >>71 お前が、というより最近の奴が何故 「俺の知ってる言語の『優位性』」に固執するのか甚だ疑問ではある。 ただ、お前は>>37 も理解出来てないのだから、まずは「オブジェクト指向」を理解した方がいいぞ。 >>74 JavaScripterはそれ以前で、オブジェクト指向そのものを知らない奴が多いし、 他言語から来た奴は無理に「クラスベース」として捉えようとして誤解し、 しかもそれを垂れ流して間違いを再生産し、どうしようもない状況になってる。 JavaScripterには馬鹿しかいない。これは断言出来る。 >>76 俺はもう動けばいいだけなら普通に作れるんだよ。 その上で、C++の動作速度が遅く、記述がかったるいのを何とかしようと試してる。 先に言っておくが、俺はC比同速程度を目指している。 スマポ(キリッなC++なんてJavaよりちょっと速い程度しか出ないし、それなら俺はCLIを使うからそれでいい。 ただしC流の書き方は見た目分かりにくいから、 C比で遅くならない、或いは多少程度でもうちょっとましに書けないか試している。 今回のにしたって、最速はC流の「頭で全部分確保、ポインタで細切れにして渡す」に決まっている。 ただこれは見た目何をやっているのか分かりにくいし、関数に分割もしづらい。 クラスにしたって、仮想関数なしなら速度もメモリもオーバーヘッドはない。なら使わない手はない。 そういう、C比オーバーヘッド無し(或いは僅か)程度で、どこまで分かりやすい見た目になるかを試してる。 楽に書きたいだけなら、JavaScriptが現状最強だ。 C比5倍程度であの楽さ、他の言語なんてやってられない。 速ければいいだけならCだ。ただし記述が見た目分かりにくいのは否めない。 それでC++でどこまでCを改善出来るかを試している。メソッドチェーンもそれの一環だ。 Cでわかりにくいコードを書くには 頭悪いという才能がいる >>80 携帯とPCで書いたから同一人物とわからんかったかな 何か実現したいことがあって >・derived等、継承で親のメソッドを使ったときにも「呼び出し側の型」を返す為のキーワードの整備 と書いてたんだと思って、解決策になるかもしれない情報を教えてあげようと思ったら 感謝もせんとC++に対するヘイトを垂れ流すだけだったから「ああ、あいつか・・・」となったんだが >「俺の知ってる言語の『優位性』」に固執する どこをどう読んだらそうなるのかわからん。というか鏡見ろ 遅いのはオマエのウンココードのアルゴリズムのせいだからな 気にする必要ないほどのオーバーヘッドが問題じゃない >>72 > スタックをplacement newしたんなら自分でデストラクタ 自分でデストラクタを書かなくて済むようにコンテナを用意してるんだよ。 というか、そもそもC++の思想はそうではないか? ある意味、クラス外のコードでデストラクタを書いたら負けだろ。 そしてコンテナを用意するだけでこれを回避出来る。 それだけの話だ。 「書けばいい」の発想もいいが、俺はもうそれは十分出来るので、 書かなくて済む物を如何に増やすか、それを試してる。 結局、スクリプト言語が楽なのはここだし。 >>83 もう動作はしてるし、結果も比較して問題ないのを確認済み。 まあ、 alloca は相当使いづらいことも分かった。 >>84 いや、ワッチョイが同一だから同一人物だと認識してる。 > 解決策になるかもしれない情報を教えてあげようと思ったら 解決策になってないし、お前はそれが間違いだとも認識出来てない。 お前の情報は何の役にも立ってない。 馬鹿が間違ったことを言ってきて「間違ってるぞ」と言ったら「それでも感謝しろ」と言われた状況だ。 そういう考え方もありだが、俺はここではそれをしないし、する必要も無いし、するべきでもないと思ってる。 ここでは、間違ったことを言った奴は叩かれるべきだ。 そうでないと馬鹿がどんどん寄ってきて、結果、レベルが下がり、誰にとっても利益が無くなる。 間違ったことを言っても感謝されたいなら、少なくともIDやコテハンが付いてる場所へ行け。 そういうところが好きなら、そういう場所を盛り上げるべきであって、ここで文句を言うべきではない。 まぁまぁ御託はいいからお前のコードを全部さらせよ 添削してやっから あとベンチマークの結果も書いとけ IntelのC++ Composerってサポート期限切れのシリアルでも使用可能なバージョンがあるのね 知らなかったよ 2017 update7 >This update can be installed even if your support service has expired using your existing Serial Number. はじめまして ゼミの課題でc++でバカラのプログラムかいてこいって言われたんですけど 簡単ですか? まずサイコロの運動をシミュレーションするところから https://ja.wikipedia.org/wiki/ バカラ_(トランプゲーム) 客が複数いないと掛け金が流動しなくて面白くなさそう。 自分は3日あれば形にできそうではある。 待ち行列で客が待つのもポアソン分布使ってシミュレーションする必要がある devirtualizationはまだclangだけ? ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる