C++相談室 part151
レス数が950を超えています。1000を超えると書き込みができなくなります。
アホみたいなチューニングが必要なら、そもそも範囲forを使うのやめたら?
直感と異なるかもしれんが、未だ普通のforのほうが早い。 アホみたいなチューニングってのが意味不明だが
必要ならやらなきゃならん
コンテナ経由ってのがそもそも遅くなる要因
直接ポインタで扱う方が当然速度は期待できる
>>782みたいな基本ルールって
それぞれ自分の中にあると思う
それを外れる最適化がヒツヨウニなるのは極めて稀
稀であったとしても必要な時はある inline化してたらコピーが速いなんて事象は起こり得ないだろ 社内報にアウトライン化による高速化事例が載ってましたが。 >>845
うわー、すごい王さまだー。
でもなんで、はだかなの? >>840
自称高速化の専門家とやらの妄想は要らんよw >>841
自分一人でコード書いてるならテキトーに決めとけ
チームでやってるならコーディング規約に従え 他称なら兎も角、自称の専門家って他のことは分かりませんって意味でしかないよね 高速化の基本はアルゴリズム、データ構造
その辺の専門家が参照かコピーかみたいな小さな事を気にするのかな?
どんなコンテナとか無視して 他に「夏本番、キラキラ☆コーデ」というのも載ってたけど、関係なさそうだったんで読んでません。 >>854
分岐予測
キャッシュ
関数ポインタ
私がすぐに思い付くのはこのくらい コーディネートではなくコーディングの略ということはもちろんわかっています。
とはいえ、意識の階層が違いすぎて、「あ、これ関係ねーやつだな」って。 あ、そういえば。
インライン、アウトラインで思い出したんだけど。
むかしツタヤでDVD探してて、カシラモジ・・・カシラモジ・・・ってカ行探してたんだけど無い。
つぎイ行探しても、あれ??無いわ??ってなった。
で、ふとア行見たら・・・アタマモジかよ・・・ありました。 高速化の専門家って当然ハードわかるよな
わかる、つーか皇帝レベル >>865
オブライアンはアイルランド系の苗字ですね。 >>870
いろはにほへとです。
無理やりすぎますかね。 >>828
俺もちょいちょい喧嘩してるけど今回関係ないぞ 浅はかな推測が外れまくったという
珍しくも何ともない現象だな std::vectorのstd::shared_ptrを返すメソッドGetHoge()があるのですが、
for (auto e : *GetHoge())
でループすると要素があるにも関わらずループしません
auto t = GetHoge();
for (auto e : *t)
とするとループします
これは何か違いがあるのでしょうか??
MSVCです msvcならeとかtにカーソル合わせればどういう型になってるかかわかるんじゃないの >>876 さんの質問への直接の答えじゃないけど、
typeid(e)::name() とかで auto の解釈を見れば何か分かるんじゃないかな。
特定の場合に auto はどのような型を生成するか、っていう
一般的な情報って言うか規則もどこかで見られるのかも知れんけど。 >>876
範囲for文の中ではauto&&の参照で範囲オブジェクトを束縛してくれるんだけど
上の場合は束縛されるのは*GetHoge() (=中身のvector)であって、GetHoge()の戻り値そのもの(=shared_ptr)は束縛されない
なのでshared_ptrはループに入る前に破壊されてしまって、参照カウントが0になると中身も破壊されてしまう
下の場合は戻り値のshared_ptrをtで確保してるから大丈夫ってこと C++はますます書いてあることと動作の関係を掴み難くなりつつ
あるな! >>876
最初の書き方の場合、GetHoge() の戻り値は、一時オブジェクト。
一時オブジェクトの生存期間は、その部分式を含んだ完全式の終わりまでとされている。
GetHoge()が書いてある場所は、for ブロックの開始時に、最初に一度だけ評価されるが、
完全式としては、その時点で終わっている。
だから、関数戻り値の一時オブジェクトの生存期間は、forブロックに入る直前に終わってしまう。
戻り値の型は、shared_ptr<vector<T>>で、この中身を参照している shared_ptrが全て
消失した時点で中身まで deleteされる。
そのため、forブロックの中では、もはや、vector<T>が削除されてしまっているということらしいね。
2番目の書き方の場合は、shared_ptr が変数 t にコピーされているので、参照カウンタが1つ分残っている。
そのため、それが指している vector<T> のメモリブロックも削除されずに残っている。
というわけで、ループしているのに結果がおかしいというのは分かるが、全くループしない理由は余り分からない。 というか>>881の指摘通りの場合、GetHogeで初めてvectorを生成してるか
自身を元に新たなshared_ptrを作って返してることになるんだが
だいぶおかしな設計じゃね? >>883
クールパルルパクルリンパ(); ←関数 >>884
ちょっと間違ってる
範囲for文はここで書いてるように「同等な書き換え」がされて、範囲オブジェクトはここの例で言うauto&& __rangeに束縛される
https://en.cppreference.com/w/cpp/language/range-for
そして、__rangeに束縛されたものが一時オブジェクトであれば、参照束縛による寿命の延長でforブロックの終了まで生存する
だからこういうのは問題ないのよ
for(auto a: std::vector<int>{1,2,3})
あと最後に関しては破壊されたvectorを使っちゃってるから未定義動作で何が起きても文句は言えない
メチャメチャな値を取り出そうと、全くループしなかろうとその時の気まぐれよ
>>886
同意。Getという名前は不適切だな >>89
こんな機能があったとは:
Temporary range expression
If range_expression returns a temporary, its lifetime is extended until the end of the loop, as indicated by binding to the forwarding reference __range, but beware that the lifetime of any temporary within range_expression is not extended. 昔はC++は複雑怪奇、C#はシンプルで分かりやすいって感じだったけれど、
今はC#の方が仕様拡張で複雑になってきて相対的に大差なくなって来てる気がする いろいろ考えたらC++にあるアレが必要になったんだよ
アレだよアレ
わかるだろ 本来標準ライブラリーで済むものまで言語仕様に入ってやがる
それというのも標準ライブラリーがしょぼくてかつ改善が入らん
あっちはだれがやってるんだ 非バカの>>885や>>888は当然コード見た瞬間最初から全部わかってたんですねわかります、 皆さんはありがとう御座います
GetHogeは実際はEnumHogeで内部でstd::shared_ptr<std::vector>を生成して返すメソッドです
一時的なオブジェクトで書き方の違いで結果が変わるなんて知りませんでした
とりあえず、変数に代入します >>889
>参照束縛による寿命の延長
これは、ranged for 以外でも、一般的に働く機能ですか?
C++ 11から有りましたか?
それとも最近入りましたか? ていうか
>>889
>あと最後に関しては破壊されたvectorを使っちゃってるから未定義動作で何が起きても文句は言えない
>メチャメチャな値を取り出そうと、全くループしなかろうとその時の気まぐれよ
mjd?!
{
auto t = GetHoge();
for (auto e : *t) {
... // (A)
}
// (B)
}
ならt(GetHoge()が返したshared_ptr<vector<T> >は(B)になるまで生存するから
(A)において*tの要素を参照する(auto &&)することは全く問題無いんじゃ… 訂正orz,
誤: (B)になるまで生存する
正: 少なくとも(B)になるまでは生存する(参照カウンタが0より大の状態を保つ) ていうか>>889の「最後に関しては」は実は
>というわけで、ループしているのに結果がおかしいというのは分かるが、全くループしない理由は余り分からない。 (>>884)
を指していたりする? だとしたらサーセン;。n_
for文のイテレータがvectorを指しているのに対して、vectorを保持するshared_ptrの破棄タイミングは確かに
forの前でも後でも有り得るヨカン、 C++は局所的に動作を想像できない場合が多いのがなぁ。
バカじゃなけりゃマクロ使いまくったCコードも理解できるかというとそうじゃないだろうと。 もっとも
>for (auto e : *GetHoge()) { ... }
このコードで動作が不定(未定義動作)になるのはGetHoge()が返したshared_ptrの参照カウンタがきっかり1だった場合であって、
2以上だったらきちんと回るんジャマイカ、
そう考えるとなかなか>>876のお題は味わい深い…
>>900どう? 腐った代入オペレータかかれるだけで悲惨なことになる (上の話に限って言えばvector<T>のTに間してどれだけ腐った代入オペレータが定義されていようとも)
別に >>903
おまえ頭悪いなって
俺が何の下支えもなく言う場合と同じだ
俺は瞬間でもないが落ち着いて追えるケースでしかない
おまえさんは絶望感でも持ったのか? しかしまあ歳は取りたくないと思ったな
全盛時の俺にはありえんことが相次いで起きている一例だった C++のラムダって、Javaとかみたいに1文だけの場合にreturn省略できないんですかね?
[](auto a, auto b){ return a + b; } → [](auto a, auto b) { a + b } みたいな感じで。 今はムリ
検討はされてるから将来的に出来るようになるかもしれない >>907
この程度のことが落ち着いて追わねば分からないというのは
藻前は衰えたのだ Rust に慣れてくると C++ で return を書くのを忘れることもある。 >>910
ありがとうございます。C++23ぐらいを期待します >>895
てか結果を返すだけなのにスマポに入れるとか、
呼ばれる関数が結果をどのように管理するかにまで口出しするのはどうかと思うけどね >>911
my powers are weak old man. 非バカの要件にコード見た瞬間最初から全部ワカルというのが入るということは
>>894で宣言して合ったのに対し別段オブジェクションをつけるでもなく
>俺は瞬間でもないが落ち着いて追えるケースでしかない
とだけ言ったのだから彼は自ら非バカではないと告白したのである
漏れの有り様の批判に繋げられても困る >>895です
>>915
でも、スマポに入れないで返す場合、例えば、受け取った側で他で色々使いまわすから受け取った側でいちいちスマポ作る
ってことでしょうか??
というか、一般的なライブラリ作る場合どうすればいいんでしょうか??
std::shared_ptr<std::vector<YYY>>XXX::EnumYYY()
とりあえず、スマポでくるんで返してあげれば受け取り側でいかようにもできるからいいのかなと思ってるのですが。 std::vector<YYY>で返して
std::vector<YYY> XXX::EnumYYY ()
で、受け取った方で他でスマポにしようということで
auto yyy = x.EnumYYY();
auto ptr = std::make_shared<std::vector<YYY>>(std::move(yyy));
とかやればオーバーヘッド少なくスマポ作れるんです? 記憶管理という本来隠すべき実装の詳細(と多くの人が考える事柄)を
使う人が意識せねばならな続けるのは嫌すぐる、 getterがshared_ptr<T> pを返したとたん、pの寿命と*(p.get())の寿命の二重管理の責務が利用者に行く
>>876の真の原因はこれ
getterがオブジェクトのディープコピーを返したらそんな二重管理は生じないで済む
getterが仮にオブジェクトXの参照を返す仕様だとしても、Xの実体を保持するオブジェクトのY寿命と
getterを呼ぶタイミングの二重管理以上の手間にはならない
結局shared_ptr<T>を返すインターフェースは不恰好さだけが残る >>921
*(p.get()) の寿命は p の寿命と同じかそれ以上という関係であって別で管理できるものではなく「二重管理」にはならないでしょ。
この関係がある状態で *(p.get()) の寿命を期待しているところで p の寿命を保持していないのが >>876 の間違い。
本当に所有権の共有が必要ならあり得るインターフェースだよ。
でも >>919 を見る限り所有権の共有は必要なかったみたいなので、素直に std::vector を返せばいいよ。 >>922
2行目で述べている、利用者がしくれば危険性が生じるという事実と
1行目の「「二重管理」にはならないでしょ」という主張は矛盾してねえが、
本当に所有権の共有が必要ならshared_ptr<T>を使うのはアリだが、shared_ptr<T>が保持する
Tの実体のみに興味がある利用者に対してはshared_ptr<T>を使っていることを
クラスUで隠蔽する方が良い
Tが持っている演算を全てクラスUからTに委譲し、UをT同然に使えるようにするのがbest
そこまでやる手間が嫌という理由でUにTを返すメソッドU::get()を備えさせる簡易手段に訴えたとしても、
Uの定義だけ見れば循環参照にならないことをUの提供者が保証できるから
(Tがジェネリックな型だった場合の)Uの利用者やプログラム全体のメンテナーに地雷原を歩かせずに済むメリットがある ちゅか明白すぎて激しく書き忘れたが、オブジェクトTのグローバルな所有権の共有が必要な場合、
shared_ptr<T>が保持するTの実体へのアクセスの排他制御を行わねばならないが
shared_ptr<T>はこの点なんのサポートもしてくれない(せいぜい自身が使う参照カウンタの排他を行うだけ
なので、Tの排他はshared_ptr<T>をwrapしたクラスUが行う必要があり、かつ行えば十分
この点一つとってもクラスUを設けずshared_ptr<T>をTの利用者に直接返す設計のダメさ加減がワカル
gdgdだ、 >>921の通り
getで実体を返すのが一番
これを管理方法はgetする側が決めれば良い
コストが重要で
オブジェクト内部のvectorの参照やポインタを返す場合はその寿命はオブジェクトと同じで良い >>917
おまえさんはまだこっちの質問に答えてないぞ
絶望感でも感じたのか?
shared_ptrを使ってるのにディープコピーとか言い出してて
相当テンパっている様子は窺えるのだが 漏れの心の内面がC++の規格に反映されているわけでないのだから
聞くだけ無駄くね? >>926
ようわからんが、>>921がディープコピー云々言ってるのは、ようするに実体を返せってことでないの?
てか俺が管理云々言い出してややこしくさせたかもしれんけど
俺もこの場合vectorそのものを返すべきだと思う、実体を返して解放忘れでリーク、とか有り得ないんだし(何のためのスマポなのかをよく考えるべき
スマポ大好きで何もかもスマポで扱いたいんなら別だがw なんか……
戻り値をどうするかは戻り値の所有権&管理責任がどちらにあるのかを表しているんだから、「必ず実体を戻すべき」とかいうのは考え足りないだろ。
>>918ならshared ptrかunique ptr(所有権を譲渡する場合)で返すのは普通にありえる。
>>924みたいなのはshared ptrの所有権を侵して実体を破壊しているわけだから、そのコードを書いたやつをぶん殴るべき案件。
そもそも規格的に未定義じゃないの? >>929
>「必ず実体を戻すべき」
俺はそんなこと言ってないけども
shared_ptrのshared_ptrの(無限ループ)でも返せというのか
>>885を読み直せ、結果を返してるだけなんだぞ?
しかもそれで参照カウントがゼロになるって言ってるんだがw
意味わかるよな? 参照カウンタがゼロになることから
getのたびにvectorを作成しており
その管理を呼び手に委ねてることがわかる
こんなものは素直に実体を返せば良い
呼び手がスマポで管理することも出来るし
特に管理せずスコープを抜けた段階で自動で破棄することも出来る 内部で管理してるオブジェクトの見せ方は色々あって難しいけど
今回の場合は新しく作ったvectorでしょ?そんなもんそのまま呼んだ奴にくれてやれよ
無駄な包装紙付けられたり、後からやっぱ俺のものとか言い出されたらウザいだろ?いらん未練残すな >>935
「この場合」って、実装見ないとわからない話では?どっかで実装の話出てたっけ? あー、調べてみたらNRVOは未だに保証は無いのな
まぁ何にせよスマポにする理由は無い >>941
876の話してるんだろ?
return value optimizationつまり最適化は関係ない >最適化は関係ない
>>934に言えよ
コピコンもムブコンもある、あるいはより正確にコピーもムーブも可能、と言ってたならわかるが >>944
934は俺だが最適化の話はしてない
vectorにshared_ptrを使うことの是非を論じている >>947
質問てコピーのことか?
除外も包含もしてない言及してないので答えようがない あ、もしかしてshared_ptr使ってんのにディープコピーとか言ってたコレ◎か? >>949
それ俺じゃないよ
てかあそこでムブコン言い出すあたり、ムブコン書いときゃおkみたいな初心者(玄人ぶりたい初心者)だと思って軽く突っ込んだだけなんだがな
ディープコピー言ってた奴も別におかしな事は言ってねーだろ、スマポ使わずにコピーを返せってことだろ?(そもそも質問者のコードはオブジェクトが管理してるものじゃないようなのでアレだが
まぁ指摘したところで逃げられるしもういいよ、悪かったな
>>942
思ったところで書く必要あるか?それ 観客へのアピールだったり警鐘だったりするんだろう本人の中では
余計なお世話かも知れないし役に立つかも知れない レス数が950を超えています。1000を超えると書き込みができなくなります。