【初心者歓迎】C/C++室 Ver.102【環境依存OK】
■ このスレッドは過去ログ倉庫に格納されています
エスケープシーケンスやWin32APIなどの環境依存なものもOK そのような質問は必ず環境を書きましょう 半角空白やタブでのインデントはスレに貼ると無くなります コードを貼れる所 http://codepad.org/ https://ideone.com/ 前スレ 【初心者歓迎】C/C++室 Ver.101【環境依存OK】 https://mevius.5ch.net/test/read.cgi/tech/1500329247/ Base Pointer : 100〜119 Derived Pointer : 120〜139 こういう状況で、Base クラスを指す際、クラスポインターは100 を指している。 100〜119 内で、Base クラスの変数・メソッドのアドレスを探す Derived クラスを指す際、クラスポインターは自動的に、120 に変わる。 120〜139 内で、Derived クラスの変数・メソッドのアドレスを探す >>607 単なる文法エラーだからエラーメッセージみてコードを直してください >>609 文法エラー?? https://ideone.com/k7g2nn の今回の部分と関係ないエラーは無視してください。 あくまでイメージ目的でそこらへん適当にやりました。 すみません。 https://ideone.com/QxErKY こっちですね。 CBaseAのmethodAをCBaseBを実体化して呼びたいんだよな? ならCBaseAとITestBどっちのmethodA呼ぶのかあいまいって怒られる これならok https://ideone.com/FGHyda もちろん、エラーなくしてコンパイルを通す方法は >>607 の >ITestA::methodAをCBaseBでまた実装しなければいけないんでしょうか?? で書いたようにすればとりあえず、コンパイルは通ります。 聞きたいのは、 C#の場合はBaseAの方で一度MethodAを宣言・定義すればいいのですが、 C++の場合は毎回CBaseAの派生クラスでmethodAを宣言して定義しなおさなければいけないのでしょうか?? それともC++では他の方法があるのでしょうか? >>612 あ、すみません。ちょっと被ってしましましたね。>>613 は忘れて下さい。 >>612 のコードを見てみます。 >>612 そっか。純粋仮想関数じゃなくて仮想関数にするって手もありましたか。 まぁ、インターフェース的なクラスの方をいじくるのが気になりますが。 ありがとうございます。 実装とインタフェースの両方を継承するならこういう書き方もある ATL なんかがこれ式かな https://ideone.com/B7JWER >>616 >>617 色々ありがとうございます。>>617 がよさそうなのでこれで行こうかなと思います。 巨大なファァイルの読み込みに関してです。 たとえば1000行のテキストからなるファイルの1000行目だけを読み込んで、配列に 代入したいのですが、ファイルをopenしていきなり1000行目にアクセスする方法はありますでしょうか? 現在、forループで1000回廻して1行ずつ増やしてアクセスし1000回目にfgetsで読み込んで配列に入れているのですが、999回のループが無駄なので高速化したいのですが、どなたかご教授いただけないでしょうか? 行という概念が 先頭から読んでいって逐次確認しないと行の区切りが確定しないのでどうしようもないんじゃない? ファイルサイズ分一気にオンメモリで読んで後から行の切り出しするとかの工夫はあるだろうけど >>619 テキストのフォーマットによっては高速化は可能 例えば1行が固定サイズとか行番号が書いてあるとか 全く自由なフォーマットだと頭から解析するしかない 読み込みスレッドと解析スレッドを分けると速くなることもあるかも 同じファイルが複数回指定されることが多ければ ファイル名と更新日時と1000行目の位置 のデータベースを持つとか >>619 「1000行目」の定義が先頭から数えて999番目の改行の次、である以上ありません。 1行のバイト数を全て同一にすることができれば(この場合しばしば行ではなくレコードと呼ばれる) 1000番目のバイト位置を計算してそこから読むことができます。 FILE * を用いてシーケンシャルにたくさん読む場合は setvbuf でバッファサイズを拡大しておくと高速になることも多いので試す価値はあるでしょう いろんな行に何度もアクセスするなら、 全てメモリに読み込んだ上で各行の先頭位置を配列に記録しておくと良いでしょう。 末尾にseekして、適当に戻って読んでみて、 改行がなければまた戻って、を繰り返すのが現実的。 巨大なファイルの中途の行じゃなく、ファイルの最終行だけを抜き出したい のか? 対象のテキストファイルとは独立に、 「そのテキストファイルの各行がファイルの何バイト目から始まるか」 という情報を覚えておく手はあると思うけど、整合を保つのが面倒よね。 >>622 の後半部分だな。 皆様いろいろご指導ありがとうございました。 私の能力では難しそうですが、いろいろ高速化を試してみます。 末尾にseek して1文字抜出し(末尾が\n の場合はそれを無視して) \n が現れるまで1文字ずつ戻りながらキューに積んで 最後にキューの中身を逆順にする 配列の要素数が分からないときscanfで読み込んだ値を要素数にするにはどのようにしたらよいですか? >>628 scanf("%d",&n); int array[n]; //読み込んだ値を要素数にするってこういう事? 基本的な事なんだろうけど、vectorを範囲ベースのforループしたいのですができません。 auto v = vector<int>()だとfor (auto &i : v)でいけるのですが、 newした場合はどうすればいいのでしょうか? autov = new vector<int>(); for (auto &i : v)だと begin関数が見つかりませんといってコンパイルできません。 どうすればいいでしょうか? すみませんでした。普通に逆参照すればいいのか。 auto v = new vector<int>(); for (auto &i : *v) MFCのアプリで排他制御のルーチンを作っていて疑問に思ったことなのですが、 CやC++の仕組みのことなので、こちらで質問させていただきます。 複数のスレッドから呼ばれる関数の内部は、 CCriticalSectionを使って排他制御しています。 void Test() { static CCriticalSection cs; cs.Lock(); : cs.Unlock(); } 関数内のstatic変数は、その関数が初めて呼ばれたときに 実体が作成されると理解しているのですが、 1回目のTest()でCCriticalSectionのコンストラクタを実行している最中に 他のスレッドがTest()を呼んだ場合、このコンストラクタ自体は、 正しく排他制御されるのでしょうか? コンストラクタが終わるまで、他のスレッドは待ってくれるのでしょうか? それとも、CCriticalSectionの変数は、 関数の外に置かなくてはいけないものでしょうか? MFCの内部でも、AFXPlaySystemSound()などで 同じようなことをやっているようなのですが。 >>633 C++11 でローカルなスタティック変数の初期化はスレッドセーフであると定められた。 (C++03 にはこの規定はなく、実際その頃はmsvcもgccもスレッドセーフではなかった) msvc では 2015 から。 c言語バージョンの指定のほか、専用のオプションによっても有効化、無効化できる 以下を参照 https://docs.microsoft.com/ja-jp/cpp/build/reference/zc-threadsafeinit-thread-safe-local-static-initialization gcc / clang では -fno-threadsafe-statics オプション 他の言語ではコンパイルエラーで悩むことはないのですが、コンパイルが通らなくてかれこれ2日。 エラーの行番号見ても、あってるよーな?よくわからない。 どうすりゃいいの。 >>636 コードすら貼らないオツムの足りなさじゃ諦めろ >>634-635 ありがとうございます。 VSは2015よりも前なので、このやり方はダメってことですね。 関数の外に置くようにします。 MFCの内部ではやっちゃってますが。 なんだよ。このクソ言語。やっとわかったわ。 ちょっとずつコンパイルしていかねぇとダメじゃん。このクソ言語。 エラーの内容はhファイルの方に"{"が期待されるところに"}"がありますなエラー。 ヘッダファイルと睨めっこしても、{}の数あってるし仕方なくcppファイルの方の実装の中身を全部コメントアウトしたら コンパイル通った。で、cppファイルの方を数行ずつコメントアウト解除したらエラーわかったわ。 hファイルにエラーがあるとかミスリードしてんじゃねぇよ。 エラーも貼れないなら、助けるのはムリ。 テレパシーは秘密保持違反になるから、このスレッドでは君を助けられないね。 つーか、仕事中にパソコンで5チャンネル閲覧記録は、大きな企業なら会社にチェックされているだろうね。 そりゃ、ソースコード全部張れば分かるとは思うけど、 エラーの内容は 「hファイルの方に"{"が期待されるところに"}"がありますなエラー。」 みたいなエラーでて、この意味ぐらい自分で分かるし。 だから、このエラーの内容だけ張っても君たちが分かるとは思えなかったら張りませんでした。 お手数かけました片山さん。 May the source be with you. そうでしたか。まだ、C++やりだして1週間未満なものでして、そういうノウハウというか関連知識が ありませんでした。 まだ、Visual Studioの「エラー一覧」ウィンドウしかまだ見てないもので。とりあえず、初心者の自分は 頻繁に数行書いたらコンパイルすることにします。 プリプロセッサによる不便さだから c++ の文法とは全く関係ないけどな >>642 今後のためにそのエラーになる最少構成でやってみ ヘッダファイルがこんなふうにconst用と非const用の関数があるとして class A { B b; B& get() { return b; } const B& get() const { return b; } } このBがくっそ長くて書くのが面倒な場合、autoで代用するのはまずい習慣ですか? auto& get() { return b; } auto& get() const { return b; } >>653 型の別名を定義することについての是非は置くとして、 typedef はオワコン。 using を使うのがモダンな C++ やで。 typedefやusingはなるべく使いたくないんですよね やはりヘッダーの返り型くらいはちゃんと記述すべきですかね イタレータとか長くなりがちだけど・・・ こうだな。動くかどうか知らんけど。 auto& get() { return b; } const auto& get() const { return b; } 柴田望洋訳のC++の本とロベールのC++の本以外にまともな日本語のC++の本ってありますか? ロベール、独習(Herbert Schildt)、柴田望洋、林 晴比古 修験者になって、数年山籠もりしたいのなら(笑)、ドワンゴ江添の、 C++11/14 コア言語、江添 亮、2015 >>660-661 ありがとうございます。 Herbert Schildtの本は、ロベールに比べると細かい話がないように思います。 柴田さんの中級という本も細かい話がないように思います。 vector について質問です。 コピーコンストラクタ、operator= について一応勉強したのですが、 vector などのクラスでは、 コピーコンストラクタや operator= はどうなっているのでしょうか? 実際にヘッダ読んで見るしかないと思うが ディープコピーしてるよとしか Visual Studioなどでデバッグするとヘッダーが見れるよ。vectorはテンプレートのクラスだから、 読み進めるにはテンプレートの知識が必要かもね。 >>664 ありがとうございました。 ディープコピーでしたら、使う上では、何も考えずに関数の引数として渡したり、 関数から返したりしてもかまわないですね。 >>665 ありがとうございました。 >>666 それはディープコピーのコストがかさむのでおすすめしない >>666 >何も考えず引数で渡しても良いですね 何をもってして「良い」と評価するのかはわかりませんが、 そういうのは拙い知識で独断せずそこら中にある 経験豊富な先人の書いたコードを読んで真似するのがいいですよ 引数は大抵 const 参照で渡しているでしょう class TestA { TestA() {} ~TestA() {} }; class TestB { TestB() {} ~TestB() {} TestA getA() { return TestA(); } }; int main() { TestB b; TestA a = b.getA(); } TestBクラスの getA() メソッドがこのテストコードで正しく動作しているのですが、TestAの インスタンスは一体どこで作られてるんでしょうか? TestA getA() { TestA a; return a; } としないでいきなり reurn TestA() で良い理由が良く分かりませんでした。 >>669 どこのメモリにどう作られているのかという質問だと思うけど、 C や C++ では式の値として構造体やオブジェクトが認められていて、 コンパイラがどこぞにメモリを用意して上手いこと作ってくれることになっている。 式や式の一部の値としてだけ現れて変数に格納されないオブジェクトはテンポラリーオブジェクトとか言うので、 詳細はテンポラリーオブジェクトでぐぐって。 >>669 のmain はテンポラリーオブジェクトを使って b を用意せず TestB().getA(); ともかける ところで今回の質問の、関数の戻り値に関するコンパイラの動作は 「戻り値最適化」なる最適化によって色々複雑なことになっているので これは自分で戻り値最適化でググって調べて欲しい。 >>669 質問が文法的なことについてだとすると、式中の項ととして TestA() std::string("foo") などのように型名にコンストラタの引数を加えて関数呼び出しのように書くと テンポラリーオブジェクトを生成してそれを値とする頃ということになる。 例 size_t l = std::string("abc").length(); std::string 型のテンポラリーオブジェクト(中身は"abc") が作られ、 それのメンバ関数 length が呼ばれ、l はその値(3)で初期化される。 >>670-671 詳細をありがとうございました。 大変良く解りました。より深くは自分でググってみます。 for (int i = 0; i < n + 1; ++i) {;} とやると、 i が n + 1 未満かどうかの判定をする際、毎度 n + 1 を計算してそれを i と比較するということになるので しょうか? もし、そうなら、 m = n + 1 for (int i = 0; i < m; ++i) {;} としたほうがよいのでしょうか? >>674 ただの整数の足し算程度なら最適化されることが期待できるのであまり気にしなくていい。 https://ideone.com/TVzVzF 上記のコードで、read関数を持ったIReadableクラス(基底クラス)があって、そのクラスから派生したCFileReaderクラス、 直接は派生していないけどread関数を持ったCMemoryReaderクラスがあって、その両方を受け取れるvector<IReadable*>を作りたいのですがコンパイルが通りません。 どうしたらいいでしょうか? どなたか教えてください。。。 >>674 いまだに最適化されないコンパイラもあることはある 8bitマイコンとかの話 あと、nがvolatileだと当然毎回計算する nがSFRだったり複数スレッド共有変数だったりするなら気を付けよう 普通は気にしなくて大丈夫 コンパイラの最適化の基本の基本なので このループの比較がパフォーマンスに大きく影響するなら 高速化テクニックは色々とある >>677 なんとなく互換性のある read を持つものをエンベロープして IReadable になるエンベロープクラスを用いるのはどう? ifstream も IReadable じゃないからエンベロープする。 https://ideone.com/27yhhu >>674 > for (int i = 0; i <= n; ++i) {;} for ループといえばつい手癖で for (int i =0; i < count-1; ++i ) {...} と書いてて、 後日に count を int から size_t にしたとき countが0のケースではまったことがあるなあ for (int i =0; i + 1 < count; ++i ) {...} と書けば良いだけなんだけど >>681 それcountが1でも全くループしないというヘンテコ仕様だけど そんなもの手癖で書くの? >>683 隣り合った2項、例えばv[i] と v[i+1] を用いた処理をするとか 後続のものがある項だけ処理するとか良くある int **a を利用して2次元の動的配列を作ります。 a を関数に渡して、計算に利用します。 2次元配列 a の要素は変更しないので、 int func(const int **a){ ... } としました。 main 内には以下のように書きました。 ret = func(a); すると、 a を int** から const int** に変換できませんというエラーが出てしまいます。 これはなぜでしょうか? >>675 >>678 >>680 ありがとうございました。 >>683 そんなにヘンテコでもないと思う for (size_t count = 0 ; count < 10 ; count++){ for (size_t i = 0 ; i < count - 1 ; i++){ .... } } こんなのはありがちかと >>687 レアケースっていうか nが小数の場合だな ふむ、なくはないか。 やはり条件の方に+1とか-1とか書くんじゃなくて初期値変える方が素直だろうな。 最適化の下手なコンパイラ対策も含めて。 >>689 だからそう言うのをレアケースって言ってるんだが... よく書くと言うなら多分住む世界が違う >>685 具体的なコードは以下です: int func(const int **a) { return 0; } int main() { int n = 10; int **a = new int*[n]; for (int i = 0; i < n; ++i) { a[i] = new int[n]; } func(a); for (int i = 0; i < n; ++i) { delete[] a[i]; } delete[] a; } >>692 さくらの続編を放送してる今日この頃、レイアースの第三章もワンチャン有るかもな! >>687 そんな事言ったら countが0でループだってレアケースだぞ >>693 const付きに変換出来るのは ポインタの先がconstに変わる場合 int finc(int * const * a) なら大丈夫 ありがとうございます。 const についてよくわからないのですが、 func の中で、 a[i][j] = 1; みたいなことをできないようにしたいのですが、どうすればいいでしょうか? >>679 ありがとうございます。その方法で取りあえずの目的は果たせそうなのですが、ほかの方法はないでしょうか? というのも、他のクラスでラッピングしたりキャストしたりせずにifstreamを食わせたいのです。 たとえば、STLの各種関数はポインタでもvector等のコンテナでも大体OKですよね? あれと同様に関数ポインタでもクラスのインスタンスへのポインタでもread()を持つものなら何でも突っ込めるようにしてforでぶん回したいのです。 標準のコンテナや自作クラス等の違いを吸収できるような構造にしたいのです。条件が後出しになってしまって申し訳ありません。 キャスト が一番コストが少ないと思う 関数の中で delete [] a[i]; a[i] = new int[10]; は出来ても良いの? >>699 ありがとうございます。 ちょっと回答が理解できないため、質問を代えさせてください 以下のプログラムの func はNGなのに func2 はOKなのはなぜでしょうか? int func(const int **a) { return 0; } int func2(const int *b) { return 0; } int main() { int n = 10; int **a = new int*[n]; for (int i = 0; i < n; ++i) { a[i] = new int[n]; } func(a); int *b = new int[n]; func2(b); for (int i = 0; i < n; ++i) { delete[] a[i]; } delete[] a; delete[] b; } >>701 それは c / c++ の欠点の1つで、 T * は const T * に文句も言わず変換してくれるが T ** は const T ** に変換してくれないという問題 T は const T と定数性以外 compatible だよね、という判断を 1 段階しかしてくれない。 キャストが必要 const_cast<const int**>(a) など >>702 皆が言っているのは質問の内容とはちょっと違うけど、 func の中で a[0] = 0; などを禁止するために内側のポインタ自体も const にして const int * const * にした方がいいよということ いやごめん func(int * const * )にすればコンパイル通るのか… T * const * ==> const T * const * という変換は暗黙でokなのか 自分がバカでした >>703 欠点なの? T ** を const T ** に勝手に変換されると困るんだが。 T * を const T * には勝手に変換するけどな ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる