C++相談室 part155
■ このスレッドは過去ログ倉庫に格納されています
>>383 それ以外にも、template引数に「...」があったり、それを使う場所でも「...」 があったりして、それぞれの意味や展開のされ方を正しく理解するのは難しい。 コンパイラがどういう解釈をするのか途方にくれることが有った。まるで 魔法のように見えることすら。結果的な意味は何とか分かっても、コンパイラが どういう原理や順序で理解したりコンパイルしているのか深く理解できないこと が多かった。 最新のSTLのソースをちゃんと理解できるまでC++を理解するのは、C++を 本格的に勉強する必要がある。 >>384 古いC++にも「initializer list」という言葉はあったが、C++11以降は 独特の概念が追加され、それに関連したオブジェクトを関数の引数にとったり できるようになったりして、それの働きを深く理解するのがまた難しい。 また、全体的に lvalue, rvalue に加えて、xvalue, prvalue, glvalueを正確に 理解し、何がどれに属するかを徹底的に理解してなければ、STLのソースコードを 正確に理解することはままなら無い。 僅かでも理解してないことがある状態でSTLのコンテナを独自に継承した テンプレートを作った場合、思わぬ不具合やメモリー関連の原因が特定しにくい バグをアプリ開発で忙しい時に遭遇してしまうかも知れない。 間違ってるかも知れないが、 initializer_list<T> は、「list initializer」に関係したテンプレートで、 登場したのはC++11移行なはず。 一方、member initializer listや、class initializer listは、名前が同じだが 全く別の概念なはずで、コンストラクタを関数定義する時に、 : MyBase(0), m_x(x), m_y(y) のように書く部分。 initilizer list と list initializer はかなり異なった概念なハズだが、 後者に関係したオブジェクトの型は、initializer_list<T>と書くようだ。 間違っていれば指摘して欲しい。 間違ってるかも知れないが、 initializer_list<T> は、「list initializer」に関係したテンプレートで、 登場したのはC++11移行なはず。 一方、member initializer listや、class initializer listは、名前が同じだが 全く別の概念なはずで、コンストラクタを関数定義する時に、 : MyBase(0), m_x(x), m_y(y) のように書く部分。 initilizer list と list initializer はかなり異なった概念なハズだが、 後者に関係したオブジェクトの型は、initializer_list<T>と書くようだ。 間違っていれば指摘して欲しい。 クラス A の中で他のクラス B のインスタンスをメンバとして持ちたいとき、B のコンストラクタに引数を渡す方法が初期化リストくらいしかない つまり後でわかる情報を使って B のコンストラクタを呼ぶ方法がない B じゃなくて B のポインタを持てば良いって思うかもしれないが、こんなどーでも良いところでポインタの使用を強制する言語仕様ってゴミだろ もーちょい頑張んなよ、C++クン using namespace std をヘッダファイル内で使いたいです。なんせ短くなるので でも、そうすることでリスクを負うというのもわかります どう折り合いをつけるべきでしょうか 皆さんはどうされていますか >>381 メンバ関数追加するだけならまぁ問題は思いつかないけど(スライシングや非仮想のデストラクタはメンバ変数追加が無ければOK ただ素のvectorからの代入やコピー、ムーブコンストラクトは出来ないので追加で書いてやらないといけない さらにそのメンバ関数を呼ぶには派生型にキャスト(コピーとか防止のために参照でキャスト)をいちいち書かないといけない まぁそんな面倒な派生クラス使うくらいならフリー関数にしといた方が楽だよね そんなこんなで安易な機能追加のための継承(まして継承される前提でないクラスを)ってのは普通避ける >>391 ARM C++のコンパイラ使ったら? #include <iostream.h> これならstd空間が元々ないよ コンテナは継承するまでもないほど完成されていること、 コンテナを継承するくらいならコンテナをメンバ変数にもつクラスを定義したほうが機能拡張や仕様変更に対応しやすい などなどでしょ >>393-394 でも例えば公開するとかなってくると当然 using namespace std; は問答無用で除くべきですよね? あと近い話で、マクロってどこに書いたら良いんでしょうか REPマクロ等を多用するんですが、同じマクロをいろんなヘッダファイルの冒頭に書くのって変ですか? 共通するマクロは、親に該当する utility.hpp みたいなヘッダファイルを作ってそこに書く等するべきですか? >>397 ああ、それなら俺もやる 開発初期はusing namespace std;で色々試していて 公開がちらついてきたあたりで律儀にstd::を書くスタイルに変えていく 自分はC++17でusingディレクティブでなくusing宣言のパック展開使ってるけど、(using std::cout, std::endl, std::string; とか) これも好ましくないのかな using std::* したいスコープを独自の名前空間で囲めば他人に迷惑かけずに済む マクロは名前空間を超えるので他人に迷惑かけやすい >>401 その理屈だと、公開するプログラムにおいてはマクロはよほどユニークな名前じゃない限り使うべきじゃないってことですか? ヘッダーファイルでマクロを定義するなら名前衝突を警戒すべきであって理屈とかじゃなくてマナー >>397 ユーザーにincludeされるヘッダじゃなくてcppでだけusingすればいいやろどうせ実装書かないんだから (テンプレートとかでヘッダに実装書くならすでに出てる通り名前空間に隠すとか >>402 まず被らない名前ならいんじゃね それかundefするヘッダも作って使い終わった段階でそれをインクルード Windowsのmin,maxとかAppleのcheckとか 考えなしの公開マクロ名は使う側に大迷惑だから慎重にしないといけない minとmaxが関数型マクロなのはやさしさ #include <Windows.h> #include <stdio.h> #include <algorithm> int main() { int a = 3, b = 4; //int x = std::max(a, b); // NG! ビルドエラー int x = (std::max)(a, b); // OK printf("x=%d\n", x); } #include <windows.h> #undef max #undef min >>398 >>401-403 namespace hoge { using namespace std; プログラム本体 } って書いておけば他と干渉しないんじゃないの >>409 ×留数とかもう忘れた・・・ ◎留数なんて勉強してません高卒てすから 学歴コンプレックスって醜いよね〜 ところでラプラスって何ですか? ラプラシアンなら知ってるんですけど Lhaplusのことですか? >>409 そういうのは小さい次元,2x2あたりで計算してみて、大きい次元でも成り立ちそうだなと納得するのが早いかもですな つか人生相談は板違い、 一生虐げられ続ける弱キャラとしての宿命がC++の規格書に書かれているなら話は別だが ヘッダオンリーライブラリの体で自作のプログラム配布するときって、全体を namespace でくるむのがマナーなんですかね 普通な名前の関数を定義したりして衝突したら不味いから? >>417 もしプリコンパイルヘッダーに #define NOMINMAX #include <Windows.h> と書いてしまった暁には、マクロ版のmin()やmax()を使いたい人は どうやって生きていくんじゃ…… boost の多次元配列ライブラリ multi_array を使ってるんだが、両辺の shape が違うときに = で代入できないのがストレスなので、引数の shape が違うときには左辺を右辺と同じようにリサイズしてから代入するように = の定義を変えたい 演算子のオーバーロードってテクを使えば良いらしいが、これは諸刃の剣で注意が必要みたいな記事を見て戦々恐々としてる、、、 代入演算子のオーバーロードで最低限気をつけるべきことってどういうものですかね 気をつけるべきこと 代入演算子を一時的なストレスでオーバーロードしない 代入はグローバルに書けないはず メンバとして書くしかない->multi_arrayのヘッダを書き換えるしかない new して確保するわけじゃない、既存の変数のアドレスを格納するだけのポインタって別にスマートポインタじゃなくて生ポで持てば十分だよね? 生ポでいい用途を自信を持って判断できず「念のため」スマポ使うやつでも見かけた? 用途次第だけどnullにならない分参照の方がいいかもしれない もしくはshared_ptrと一緒に使うならweak_ptr >>426 後出しですみませんが、vector の各要素へのポインタを vector で持つ事も考えてます 参照の vector は普通には持てないので、その意味でももう生ポインタの vector で良いかって気になっていました reference_wrapperなら参照vector作れるけど、そこまでしたくないってことならポインタでいいんじゃない 気をつけてな 考えるべき所がズレてる 既存の変数はポインタを保持してる期間に必ず存在しているか 別スレッドから既存の変数へのアクセスが発生するか 表記方法を考えるのはその後 >>423 こういう場面では生ポインタでいいよね? っていう意味? #include <memory> int main(void) { int a; std::unique_ptr<int> b(&a); } むしろ不必要に解放しようとしてワヤになるんで、生ポインタである必要がある。 デリータが何もしないようにすればスマートポインタでも大丈夫ではあるけど、 あえてそうする必要もないし。 >>427 std::vector は要素を追加するなどしたときに再配置が起こる可能性があるから 要素へのポインタ (または参照) を持つのはあまりオススメできない。 (インデックスで持ったほうがいい。) 適切に管理できるならポインタでもそれほど問題でもないんだけど、 質問の雰囲気を見る限り十分な理解があるような感じでもないので……。 vectorの中身なら 要素の参照やポインタ vectorの参照やポインタと要素のインデックス イテレター 色々と持ち方があるから 場面場面において適切なのを選ぶ メモリ管理をしてないのにスマポで保持は無い >>430 > std::vector は要素を追加するなどしたときに再配置が起こる可能性があるから > 要素へのポインタ (または参照) を持つのはあまりオススメできない。 > (インデックスで持ったほうがいい。) 再配置が起きたとして、ポインタが指してる先が危険にさらされることなんてあるんですか? newした新しいメモリにコピーして古いのをdeleteしたら古いのを指してるポインタはもう使えんだろ ほら最近初心者への教え方がおかしい&最初からスマポ押し付けるからこういうのが出てくる・・ いや new や delete はしないって書いてあるよ よく読んでおじいちゃん 最近のC++が難しく感じる原因は、cppreferenceに頼ってる人が多いから ではないか。あそこはドキュメントの品質が悪くて混乱の原因になる。 C++は、代入/コンストラクタがmove系とcopy系で原理的には好き勝手にプログラム できるので、バグが出た時にプログラムの流れを追うためにはmoveとcopyのどちらが 呼び出されているかプログラマがコードから明確に区別ができないと困るね。 その点、デフォルトmoveで、xxx.clone()としない限りは複製されないRustの 設計思想はそれはそれで便利と言えるかな。 どちらが優れているかは一概には分からないかも知れないけれども、デバッグ 時の追いやすさの観点からすればRust流の方が良いかな。 >>438 C++の場合は、x=std::move(y);と書けば明示的にmove系が呼び出されるので その場合、混乱は生じないが、右辺が関数の戻り値が構造体型/クラス型の場合、 RVO(Return Value Optimization)が働いたり、右辺が「クラス名(引数列)」 のようなテンポラリオブジェクト作成の場合にはmove系が選択される という「自動振り分け機能」があり、自分が知らないだけでそれ以外にも 特殊なパターンがまだあるかもしれないことが、不安や予想しづらい 原因になっていると思う。 Rustの場合は、自動化されているかと思いきや、実際には、代入などが move/copyのどちらになるかに関しては、自動ではなく、 デフォルトmoveで、x.clone()とした場合にのみcopyという明示的に 区別する方式なんだと思う。 std::vector<int> v((size_t)3); printf("&(v[2])=0x%p\n", &(v[2])); v.resize((size_t)5000); printf("&(v[2])=0x%p\n", &(v[2])); ↓実行結果(例) &(v[2])=0x000002376EF91658 &(v[2])=0x000002376EF93A08 new,deleteが起きないとかいうトンデモ理論はshared_ptr<T>のstd::vectorと混同した感じ? 数値計算畑の人間だけど、numpy with MKL が C++ より速くてワロス もうホントにニッチな領域でしか使わなくなっていくな C++ >>442 それはシングルユーザーライセンスであっても 500千円からという価格のインテル製コンパイラやライブラリを使うからなのでは? 多次元配列の添字を入れ替える関数を実装したいのですが、任意の次元に対応するものをどう作れば良いのかわかりません。 たとえば v[a][b][c] を v[c][b][a] と入れ替えるのを全ての a, b, c について行ないたいです。 次元が 3 と決まっていれば、整数 a, b, c についてループを回して v_[c][b][a] = v[a][b][c] のようにコピーすれば良いのですが、次元が任意だと鉤括弧 [][][] を用いた要素アクセスをどうすれば良いのか分かりません。 不可能ですかね? その場合、多次元配列を 1 次元で持つことにして、各次元の長さを la, lb, lc,... として、整数 x を 0 から la*lb*lc... -1 まで回して、その都度 x の各桁を取り出して要素をコピーする、みたいなことしかやりようがないですか? そうなると各桁を取り出すのに割り算とか剰余演算を駆使しないと駄目なのでパフォーマンスが落ちるのが懸念です。 あるいは、3 次元に対応した関数、4 次元に対応した関数、…… といった感じで各次元に特殊化した関数を実装するべきでしょうか? できれば一般的というか汎用の関数を作りたいのですが。。。 シングルユーザーライセンスであっても 500千円からという価格のインテル製コンパイラやライブラリ を使ってもnumpy with MKL が C++ より速いとかこの世は暗黒だな v[0]やv[i][0]が配列なのか単一の型なのかは判定できるから enable_ifで分けてオーバーロード(再帰するかしないか)とか出来るはず >>433 >>427 で「vector の各要素へのポインタ」って書いてるからそっちの話だろう >>445 MKLがIntel製で、 「Intel Math Kernel Library (MKL) というのは, Intel 製の高速な数値計算ライブラリ」 だよ。 つまり、Pythonでは、Intel製の高速なライブラリを使っているが、C++では 使って無い場合の速度比較。 >>446 なるほど…… 勉強してみますが大変そうですね 外部ライブラリに頼るか迷いますが、多次元配列は非常に基本的な機能だと思ってるので最低限度で取り回しの良いものを自分で持っておきたいという思いがあります…… 作るなら[x] [y] [z]の形にしない方が良い []の中にベクトルを入れる方が融通がきく >>452 v[ {x, y, z} ] みたいに要素アクセスするってことですか? MKLが元々c/c++のライブラリってことも知らん輩がおるのか。。 まあ確かにnumpyやってりゃ問題はないが。 MKLが元々c/c++のライブラリってことは知ってたが Pythonでシングルユーザーライセンスであっても 500千円からという価格とは思わなかった 、 >>448 生ポインタのvectorってだめなんだ やってたかも まあpush_backとかしなければいいんかしらんけど >>454 でも 「numpy with MKL が C++ より速くて」 という言葉からすれば、Pythonの時だけそれを使い、C++の時にはそれを使ってない としか思えない。 PythonでもC++でも同じMKLを使ってて、Pythonの方がC++より 速いなんて事は有り得ないだろうし。 >>456 だれも生ポインタのvectorがだめなんて言ってないから何か勘違いしてそう。 >>456 ん?ダメなのはvector要素へのポインタだぞ? >>459 だめなのであれば、std::vectorの存在意義を否定することになりかねない。 C互換の配列およびポインタを実現するコンテナはstd::vectorだけ。 危険性を分かったうえで使う、というのが正しいかと。 >>460 どういう意味で存在意義を否定することになると言っているんだろうか。 必要に応じて再配置してくれるのもvectorの存在意義だと思っているが? 昔のstd::vectorは先頭アドレスを取得するメンバ関数data()がなかったのでポインタとして使うことに多少の背徳感があった >>459 ポインタ保持中にvectorがresizeしないなら ポインタ保持で何の問題もない 要素の再配置ができない場合や要素のポインタを扱う場合は、多少効率は落ちるがstd::dequeつかえば良いと思う >>465 > vector とは異なる欠点として deque は連続した位置のストレージに全ての要素を持つことを保証していないため、ポインタ演算を介しての安全なアクセスの可能性を排除する。 https://cpprefjp.github.io/reference/deque/deque.html >>466 あぁ、連続要素アクセスは確かにだめだなw でも、連続要素アクセスならポインタなんか使わずに範囲for分なりiteretor使った方が楽だよね なるべくキャッシュに入れたいって率でメモリ連続性を求めてる人たちはたぶんそれだとキツい Win32APIなどOS固有のシステムコールはC言語を前提に作られているので、C++でその恩恵を得たいならメモリ連続性が保証されたコンテナが必要不可欠 APIがらみだとstd::arrayのheap使用版みたいなのが欲しくなることがあるな vectorだと初期化が若干面倒なんだよね >>450 ごめんさらっと言ったけど、現在の各次元のインデックスも実行時の数値として渡す必要あるし再帰と相性悪いかも ただ文法上、次元数に関わらず同じコードで、ってなるとテンプレートと再帰は必須だと思う けどそこまでしても、君が書いてた一次元で除算と剰余使うのと比べてそんな速くなるとも思えんので無理せず一次元でいいと思うw https://wandbox.org/permlink/XpJkS3veZNwNOlaQ 気になったのでやってみた、実測(一次元、および要素数決め打ちとの)はめんどいので頼む・・ numpy のAPIを C/C++ から使うのがお薦め >>473 ありがとうございます 正直 beyond me って感じですが、勉強になります こういう再帰的な定義って STL の [] も同じなんですかね? >>474 これって、numpy の記法で C++ の配列を操るというわけではなく、Python (numpy) を C++ から操るということですよね? 全ての処理を numpy の機能で行なうことにすれば、全ての計算が事実上 C++ で動くことになるから速いって感じなんですかね >>475 いや再帰してるのは単にint[I][J][K]をint[J][K]のループ、さらにint[K]のループに(配列の参照で)分解するためにやってるだけ (そうすればどの階層でもt[i]で書けるから ただこれ、コンパイル時に要素数も次元数もわかってる固定長の配列でしか使えないんだよね ポインタを要素数決め打ちで多次元配列の参照にキャストして渡すのは出来るかもしれんけど・・ まぁ要素数が実行時にしか分からなくても使える一次元での計算のが汎用性高いと思う 皆さまコロナ禍いかがお過ごしでしょうか ちょっと質問させてください 特定のクラス内部で自身の型を格納するコンテナを実体として確保し、そのコンテナから入れ子状?のような形で使用しています 私の環境では動くのですが、これを動かしても安全なのでしょうか? クラス内部には自身の型を確保できないと聞いたことがあります…… 問題が起きそうな気配がしなくもない感じがしますが 当方素人です class hoge{ Int a; bool b; vector<hoge> hoge_vec; }; このクラスを hoge Tochigi; Tochigi.hoge_vec[0].a=315; というように使っているのですが…… >>479 問題ない。 クラスは自分自身を内包できないが、 それは自分を内包した自分というものが可能だとすると 大きさが無限になってしまって確定できないからで、 参照やポインタとして持つ分にはそういった問題にならない。 std::vector の実体としてはヒープに確保した配列に要素を入れていく形になるので、 この場合に hoge が hoge を内包しているわけではない。 >>481 ありがとうございます アロケーターがコンテナ用の領域を確保してくれるので確保可能と言うことでしょうか? クラス内部で要素数ゼロのvector領域を確保してメモリを予約してるのかな? vectorの型がvector分の領域を計算できないから見た感じ不可能だと思って どういう処理してるのか >>482 std::vector が適当な大きさの配列へのポインタを持つ構造だと思ったらだいたい正しい。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる