1 名前:デフォルトの名無しさん [2018/11/12(月) 14:55:13.35 ID:Tf74ZWQr.net] 何にも知らない0からの出発、超初心者のためのC++相談室
232 名前:デフォルトの名無しさん mailto:sage [2021/05/18(火) 08:10:11.28 ID:ysWtxNVs.net] 229にこれも組み合わせ https://cpprefjp.github.io/reference/random/uniform_int_distribution.html
233 名前:226 mailto:sage [2021/05/18(火) 22:58:17.77 ID:wt3ZqlEf.net] 今C言語を学習してるのですがC++じゃないと完全ランダムは無理なのですね…。 RAND_MAXは関数なのでしょうか?Cだと使えなかったです。 教えてくださってありがとうございました。
234 名前:230 mailto:sage [2021/05/19(水) 00:18:20.95 ID:ONEwpJm5.net] >>233 「完全なランダム」とは何か定義して。
235 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 00:55:55.90 ID:g9DnnU6R.net] せっかくなのでC++を勉強してみては?
236 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 01:16:05.73 ID:OYngDuIu.net] 何をやりたい目的があるから、何々を勉強するだと、速いですよ。
237 名前:はちみつ餃子 mailto:sage [2021/05/19(水) 01:17:09.90 ID:ONEwpJm5.net] このスレは C++ スレだからな。 C++ は C との互換性のために残している機能はあるが C++ 的にあまり好ましくない場合もあるし、 完全な互換性が維持されているわけでもない。
238 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 01:36:10.61 ID:OYngDuIu.net] スレ建てといただす。 0からの、超初心者C言語相談室 https://mevius.5ch.net/test/read.cgi/tech/1621355654/
239 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 01:52:35.92 ID:yT7tFlzp.net] >>233 RAND_MAXは、古くから有るマクロ定数で、stdlib.h で例えば次のように定義されている: #define RAND_MAX 32767 説明によれば: 「rand関数が返す最大値。処理系によって異なるが、最低でも 32767以上である。」 rand()は偏りが強いには強いが、それでも 227 のように書けば 226 のように 下一桁がいつも8になるようなほどではない。
240 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 01:54:51.13 ID:yT7tFlzp.net] 少なくともrand() は、>>228 のように書けば、メルセデスツイストなどの 乱数を使わなくとも普通に使える。>>227 のように書くとダメなだけ。
241 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 10:58:56.45 ID:G7N6xM6g.net] 0から7の整数が均等確率で出る乱数をrとした場合、 x = r % 3; とすると、xは0〜2までの整数が出るが、均等確率ではない。 それはすべてのパターンを書いてみると分かる:(r,x)を書いてみると、 (0,0) (1,1) (2,2) (3,0) (4,1) (5,2) (6,0) (7,1) x= 0 となっているのは、3回。 x= 1 となっているのは、3回。 x= 2 となっているのは、2回。 なので、 P(x=0)=3/8 P(x=1)=3/8 P(x=2)=2/8=1/4 となり、x=2が出る確率だけが小さくなってしまう。 これと同様に、rが0〜32767を均等確率で出す乱数の場合、x=r % 100の値は0〜99までだが xが0〜99になる確率は均等ではない。
242 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 12:10:26.94 ID:G7N6xM6g.net] なので、もし、とても偏りの少ない乱数を用いたとしても >>227 では均等に 出現しない。 それを解決するには>>228 のようにすればよい。というか227が標準的なrand()の 使い方。 227 だともしrand()が均等確率で出ているならば、結果も均等に出現する。
243 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 13:29:25.47 ID:G7N6xM6g.net] ちなみに、rand()は、出力範囲内の整数を全て出力し終わってから元の値に 戻る様になっているので周期も RAND_MAX + 1 に等しく、出力値は 均等確率で生じる。 >>227 だと10で割った時の余りが必ず8になっておりそれは、出力が 10n + 8 になっているということ。これだと、今言った法則に当てはまって ないので矛盾し、何かがおかしい。
244 名前:デフォルトの名無しさん [2021/05/19(水) 15:03:30.63 ID:SQApMI36.net] C言語でのサーバー構築のやり方わかる方いますか?
245 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 15:05:53.17 ID:G7N6xM6g.net] >>244 HTTP サーバーのことかな?
246 名前: mailto:sage [2021/05/19(水) 19:58:38.12 ID:Y2/6iGxL.net] >>244 バークレーソケットをオープンしてリスンして、接続してきたのなら fork() だのスレッドで処理だの、というのを昔したことがありますが、すっかりわすれてしまいました… どんなサーバーが欲しいのですか?簡単なサーバーならご要望に応えてテキトーに書く準備はありますよ
247 名前:はちみつ餃子 mailto:sage [2021/05/19(水) 23:06:46.13 ID:ONEwpJm5.net] >>242 それはよくある勘違い。 >>228 の方式では均等にならない。 櫛状にばらける。 0〜32767 の乱数から 0〜99 の乱数を得るには 32700 以上の値が出たときにそれを捨てて そうでない値のときに 100 の余りをとればいい。 少なくとも私の手元の環境にある std::uniform_int_distribution はそのように実装されている。
248 名前:デフォルトの名無しさん mailto:sage [2021/05/19(水) 23:56:26.10 ID:l+JWTKLH.net] >>242 はアホと思ったけど、 こんな勘違いをするアホがよくいるって? そんなアホな
249 名前:デフォルトの名無しさん mailto:sage [2021/05/20(木) 00:27:22.67 ID:qlUu+R49.net] >>247 uniform_real_distributionの時は?
250 名前:デフォルトの名無しさん mailto:sage [2021/05/20(木) 02:25:38.74 ID:Dz+v3/+O.net] >>227 の結果は予想と外れていると思う。 rand()は均等確率のはずなのに、100で割って下一桁に9ばかり出るはずはない。
251 名前:デフォルトの名無しさん mailto:sage [2021/05/20(木) 02:28:22.34 ID:UJvm/t/I.net] >>247 なるほど。言われてみればそうだわ。 32767はもともと100で割り切れないから、一部を捨ててやらないと 均等にはならないな。
252 名前:デフォルトの名無しさん mailto:sage [2021/05/20(木) 02:52:09.51 ID:onv6EMq1.net] しかし、昔実験してみた限り、rand()の周期は、通常、RAND_MAX + 1 であり、rand()自体は均等確率のはずだ。 それはべつに、>>247 ではちみつが言っていることと矛盾するわけではない。 RAND_MAXが32767のように100で割り切れない値だから、>>228 のようにすると、端数の様な部分でわずかに均等確率からずれてしまう。 ただし、ずれる範囲は、32767/100 = 327.67 なので、確率にして 0.67/327 程度以下の小さなずれではあるが。
253 名前: mailto:sage [2021/05/20(木) 22:00:26.21 ID:+zMkmbAL.net] >>247 剰余を取って特定範囲の乱数を生成することができるのは、元の乱数が MT 並に性質がよいときだけかと、つまり >>247 はちみつ氏のやりかたは、元の乱数が優れたものだからできる方法 MT が発明されるまでは、最悪の方法「線形合同法」でもなんとか我慢できる部分範囲の乱酔生成法しか推奨されなかった C FAQ をみてもそれがわかりますね www.kouno.jp/home/c_faq/c13.html#16 13.16: A:ある範囲の整数からなる乱数はどうやったら生成することができるか。 Q:すぐに思い付く、 rand() % N (これは0からN-1までの数を返そうとする)は乱数の質が低い。なぜな ら乱数発生器の多くで下位のビットは悲惨なほどランダムでない。よりよい方法は以下のようなものである。 (int)((double)rand() / ((double)RAND_MAX + 1) * N)
254 名前:はちみつ餃子 mailto:sage [2021/05/20(木) 23:50:59.51 ID:qkpZwp6c.net] >>253 乱数ソースの性質の悪い部分を分布関数で修正するのはレイヤの分離がきちんと出来ていない感じがして嫌だな。 下位ビットを捨てるなら捨てるでそれが明示的であるほうが好ましいと思う。
255 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 00:17:02.51 ID:Q+lecBxK.net] QZからはキムチの匂いがする
256 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 10:19:44.69 ID:pMLUvwAV.net] いずれにせよ >>227 は、まともな標準ライブラリで試すと 226 のような結果に はならないはず。理由: 226では、rand()%100の下一桁が常に9だが、それだとrand()は常に奇数という ことになるが、実際のrand()は全て奇数ということはないから。 現象的には、偶数と奇数が交互に来るという不具合が知られていたりするが、 全部奇数ということはない。
257 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 10:27:54.72 ID:b4MjZLXj.net] 超初心者スレであることを考えると >>227 の srand() がプログラム起動時一度だけとも限らないのでは。
258 名前:はちみつ餃子 mailto:sage [2021/05/21(金) 13:18:40.70 ID:JT5uzYpW.net] Windows の (msvcrt の) rand は線形合同法だが下位バイトを豪快に捨ててる。 そのせいか (下位バイトを捨てない線形合同法よりは) 乱数としての質は多少良いが 初期値の違いに鈍感で、初期値が似ていれば最初の乱数も近いということが起こる。 >>257 の指摘は妥当かもしれない。
259 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 17:16:26.14 ID:qriMwFf7.net] >>257 つまり、rand()だけを繰り返しているのではなく、srand()とrand()の組を ひっくるめて繰り返しているようなことなのかな。 なるほど、それなら問題の焦点はsrand()と時刻の関係性になるので >>227 のような結果になったとしてもおかしくはないな。
260 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 17:24:43.18 ID:qriMwFf7.net] なるほど。 質問者は、だから>>228 でも快い返事をしてくれなかったのか。 彼は例えば、以下の様に書いていたようだね: (1) for ( int i = 0; i < 20; i++ ) { srand((unsigned)time(0UL)); int r=rand()%100-1; printf( "r=%d, ", r ); } 本来は、こう書くか、 (2) srand((unsigned)time(0UL)); for ( int i = 0; i < 20; i++ ) { int r=rand()%100-1; printf( "r=%d, ", r ); } こう書く: (3) srand((unsigned)time(0UL)); for ( int i = 0; i < 20; i++ ) { int r = (int) ( ((double)rand()) / ((double)RAND_MAX + 1.0)) * 100.0 ); printf( "r=%d, ", r ); } この中で(1)はダメ。(2)も余り良くない。(3)はplain Cでの簡単な書き方では 標準。しかし、わずかに均等確率からはズれる。
261 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 18:35:20.74 ID:ojw3YA/u.net] >>256 >>227 を見れば乱数になってないことは一目でわかると思うのだけど >>256 の時点で毎回srandを呼んでるのかとも思ったけど、 それにしても値が綺麗すぎる。
262 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 19:25:04.91 ID:UZ6lwfzX.net] Cはよくわからんのだけど(3)のやつわざわざdoubleにキャストする必要あるの?
263 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 20:07:22.28 ID:ojw3YA/u.net] RAND_MAX + 1 でオーバーフローするとか
264 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 20:19:47.95 ID:UZ6lwfzX.net] 最低でも32767以上だからINT_MAXのときもあるのか… ありがとうございます。
265 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 20:22:18.98 ID:UZ6lwfzX.net] と思ったけどRAND_MAX+1.0した時点でdoubleになるんじゃ?
266 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 20:30:15.34 ID:ojw3YA/u.net] >>265 なるけど 書かなくても動作が同じであれば書かない主義? カッコとかコメントとか 1.0 も 1. で良いんだよ まあそれ以前に (3) はカッコの対応がおかしいな
267 名前: mailto:sage [2021/05/21(金) 20:40:21.60 ID:XRGlJQOp.net] >>254 確かに今となっては MT が開発されてしまったので、その感覚は理解できます しかし、我々は MT がなかった頃の好き古き時代についても考慮するべきでしょう、過去の方法を評価するのに、その当時の技術的制約を考慮せずに「今の価値観」で裁断するのはフェアではない、と私はつくづく考えているのです
268 名前: mailto:sage [2021/05/21(金) 20:47:24.81 ID:XRGlJQOp.net] >>257-258 なるほど、従って >>227 に対する適切なアドバイスは次のとおりだと私は提案します >>227 MT = メルセンヌ・ツイスタを使いなさい srand() とか rand() は忘れなさい、これらは化石時代の乱数生成法だから、今となっては srand() とか rand() をあえて使う合理的理由は存在しません MT の導入方法や使い方は、次の私のソースを参考にしてください https://ideone.com/M2SRcE https://mevius.5ch.net/test/read.cgi/tech/1434079972/60
269 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 21:29:08.32 ID:ojw3YA/u.net] どう見ても乱数生成法の質の問題じゃない 使い方が間違ってる 乱数の質を求めるならハードウェアの乱数生成命令を使うのが一番だが >>227 はそういうレベルじゃない
270 名前:デフォルトの名無しさん mailto:sage [2021/05/21(金) 21:33:53.10 ID:ojw3YA/u.net] Visual Studioで以下をやったら>>227 みたいな値になった 3秒ごとにsrand/rand をコールしてるんでしょう for (int i = 0; i < 100; i++) { srand(i*3); printf("%d\n", rand() % 100); }
271 名前: mailto:sage [2021/05/21(金) 23:18:48.19 ID:XRGlJQOp.net] え? >>227 って srand() を複数回呼んでいるんですか?確かにそれは間違っていますね… srand() は普通、アプリ起動直後に一回だけ呼べば十分ですよ…
272 名前:デフォルトの名無しさん mailto:sage [2021/05/22(土) 02:03:33.66 ID:8I9NK3Yz.net] >>270 洞察すれば、こんな風だろうか? (端末で確認しながら三秒間隔でEnterキーを押している) : for ( int i = 0; i < 20; i++ ) { srand((unsigned)time(0UL)); int r=rand()%100; printf( "r=%d\n", r ); getche(); // 3 秒間隔で人間が Enter キーを押す。 }
273 名前:デフォルトの名無しさん mailto:sage [2021/05/22(土) 02:04:35.75 ID:MF6mf+kw.net] >>270 洞察すれば、こんな風だろうか? (端末で確認しながら三秒間隔でEnterキーを押している) : for ( int i = 0; i < 20; i++ ) { srand((unsigned)time(0UL)); int r=rand()%100; printf( "r=%d\n", r ); getche(); // 3 秒間隔で人間が Enter キーを押す。 }
274 名前:デフォルトの名無しさん mailto:age [2021/06/02(水) 11:54:46.08 ID:QfG+Xq1u.net] 書籍の意味が分からないので教えてほしいのですが それ以外のって部分から何を言ってるのか全く分かりません ”signed char a;である時は、aには−128〜127の数値しか入れられません。それ以外の数値を入れようとすると、普通は一番下の1バイト、つまり2進数での下8桁だけになり、上の方の桁は全て切り捨てられてしまいます。 最大値より大きい値になった時をオーバーフロー…略”
275 名前:デフォルトの名無しさん mailto:sage [2021/06/02(水) 12:23:21.09 ID:A2GTbdiP.net] 何を教えてほしいのかわからない。
276 名前:デフォルトの名無しさん [2021/06/02(水) 12:37:39.80 ID:QfG+Xq1u.net] >>275 ロベールの107ページの ”signed char a;である時は、aには−128〜127の数値しか入れられません。それ以外の数値を入れようとすると、普通は一番下の1バイト、つまり2進数での下8桁だけになり、上の方の桁は全て切り捨てられてしまいます。” ↑この文が意味不明なので簡単に教えてほしいです ”signed char a;である時は、aには−128〜127の数値しか入れられません” ここまではなんとなく理解できたのですが…
277 名前:蟻人間 mailto:sage [2021/06/02(水) 12:45:51.56 ID:1WJ2HfQ7.net] >>276 そもそもビットとかバイトとかわかるの? わからないなら、基本情報から勉強しないといけない。
278 名前:デフォルトの名無しさん mailto:age [2021/06/02(水) 12:56:19.74 ID:QfG+Xq1u.net] >>277 この前のページに2進数 1ビット 1バイトなどの単位と各型のバイト数について触れられてるので そこは何となく理解できてるのですが
279 名前:蟻人間 mailto:sage [2021/06/02(水) 13:18:03.17 ID:1WJ2HfQ7.net] >>278 1ビットは、2進数一桁で、ゼロかイチ。 2ビットは、2進数二桁で、00、01、10、11の2**2==4通り。これらは10進数で表すと0、1、2、3となる。 3ビットは、2進数3桁で、000、001、010、011、100、101、110、111の2**3==8通り。これらは10進数では、0、1、2、3、4、5、6、7となる。 …… 8ビットは、2進数8桁で2**8==256通り。10進では0〜255となる。現代では8ビットは1バイトに相当する。1バイトは16進二桁で表せる(2**8==16**2)。 以上は符号なしの場合。 符号付きの場合は最上位ビットがマイナス符号の有無を表し、正の場合は符号なしと同じで、負の場合は2の補数表現になる。
280 名前:蟻人間 mailto:sage [2021/06/02(水) 13:32:39.22 ID:1WJ2HfQ7.net] 2の補数表現というのがくせ者だが、まあ、Wikipediaの説明を見てもらいたい。 https://ja.m.wikipedia.org/wiki/2%E3%81%AE%E8%A3%9C%E6%95%B0 符号付き8ビットの場合はx+y==2**8となるyがxの2の補数となる。補数を使えば足し算で引き算を表せる。 まあ、例えば10進数4桁1234の10の補数表現は8766となる。1234+8766==10000となるが有効4桁からオーバーフロー(桁あふれ)してゼロになる。8767の場合は1234+8767==10001、 オーバーフローしてイチになる。このようにオーバーフローを前提とすれば、大きな数で引き算を表せる。
281 名前:デフォルトの名無しさん mailto:sage [2021/06/02(水) 14:31:54.50 ID:CzhBAh+2.net] お、優しい先生が現れたぞ。嘘ばかりの5ちゃんの中で珍しい。
282 名前:デフォルトの名無しさん mailto:age [2021/06/02(水) 14:44:42.56 ID:QfG+Xq1u.net] >>280 すいません詳しくありがとうございます 補数って概念全く理解してなかったので、それが原因だと分かりました。 コンピュータは足し算しかできないのですね… そこら辺知識固めてからもう一度読み直してみようと思います。
283 名前:蟻人間 mailto:sage [2021/06/02(水) 16:48:03.08 ID:1WJ2HfQ7.net] 10進4桁の場合、9999に1を足すと10000、オーバーフローしてゼロになる。よって、このオーバーフローするシステムの場合、9999はマイナスイチを表していると考えることができる。 同様に9998は-2であり、9997は-3である。
284 名前:蟻人間 mailto:sage [2021/06/02(水) 16:54:31.73 ID:1WJ2HfQ7.net] 符号付き8ビットの場合、2進数11111111、つまり16進でFFがマイナスイチを表す。同様に11111110(FE)はマイナス2であり、11111101(FD)がマイナス3である。 規則性が分かると思うけど、ビットを反転して、符号なし整数と見なしてイチを足すとマイナス符号の追加と同じ効果がある。証明略。
285 名前:はちみつ餃子 mailto:sage [2021/06/02(水) 17:04:16.45 ID:Bcy6nIKX.net] 一応補足しておくけど負の数の表現が二の補数であることは C/C++ の言語仕様としては保証してないし、 (C++20 からは二の補数であることが保証されるようになった) 1バイトが8ビットであることも保証してない。 signed char に型変換したときに上位ビットを切り捨てることも保証されない。 (変換後の型が unsigned のときには実質的に保証される。) 言語仕様として保証しないからといって間違っているというわけではなくて、 一般的なコンピュータのアーキテクチャではおおよそそうなってるのが普通というのも事実。 C++ の言語仕様の一部は機械の都合 (どのような機械語を生成するのが効率的か) でいくつかの選択肢 をとれるように言語仕様の側では意図的に決めてない部分がある。 「C++ の説明」として見たら >>276 で引用されている説明はちょっと微妙かもしれん。 あまり踏み込んで説明するのがめんどいから「普通は」という言葉でごまかしているんだと思う。
286 名前:デフォルトの名無しさん [2021/06/02(水) 23:13:21.37 ID:ZuDsQZsq.net] float/doubleは
287 名前:デフォルトの名無しさん mailto:sage [2021/06/03(木) 02:59:14.77 ID:Ers5yK+g.net] char は環境依存なので使わないようにする。 unsigned・signed のどちらなのか、分からないため unsigned char は、0〜256 signed char は、-128〜127 0〜127、7ビットの範囲では、この2つは共通している signed charは、先頭ビットが1なら、負数となる。 2の補数を調べて 1111_1111・0xFF なら、256か、-1
288 名前:286 mailto:sage [2021/06/03(木) 03:03:09.44 ID:Ers5yK+g.net] >>287 修正 256 ではなく、255 です unsigned char は、0〜255 1111_1111・0xFF なら、255か、-1 だから、環境依存のchar 型を使っていると、 エラーに、-1を使っていたが、他の環境では255と表示されたりする
289 名前:デフォルトの名無しさん [2021/06/03(木) 10:13:20.76 ID:oKNqyVQK.net] むしろ int を期待してる引数に char 渡す時が危険
290 名前:はちみつ餃子 mailto:sage [2021/06/03(木) 13:38:18.86 ID:ivgy5ZU8.net] char 同士なら符号の有無が違ってもビットパターンは維持された ままで型を読み替えることが期待できる (言語仕様として保証しているわけではない) けど、大きな型に変換するときは符号拡張が起こることがあるからだね。
291 名前:デフォルトの名無しさん mailto:sage [2021/06/05(土) 22:29:47.19 ID:UR0LV/yo.net] ハーバートシルト『STL標準講座』翔泳社, 1999, p.156-157 のサンプルプログラムで、そのままだとコンパイルが通らないものがあるのですが、 適当にconstをつけていたらコンパイルできるようになりました しかし、理由がわかりません どなたかご教示いただけませんか? https://ideone.com/LGnjXo
292 名前:デフォルトの名無しさん mailto:sage [2021/06/06(日) 01:24:02.19 ID:Lz5dZs8J.net] operator <<のとこでoがconst参照だから、そのoからはconstなメンバ関数しか呼べない。のでそれで合ってる 元のソースが間違ってるか何かだと思う、この仕様は最初からのはずなので
293 名前: mailto:sage [2021/06/06(日) 01:44:38.27 ID:xlnMgrm3.net] >>291 set<>::iterator は const をつけていなくても set<>::const_iterator と同じくイテレータ≒ポインタに const 属性がつきます。 だから set<>::iterator p; …@、と宣言した場合の p には「終生」 const 属性がつきまとうことになります。 例えば@の p にポインタ演算子 * を適用して出来た表現「*p」が参照に読み替えることがあれば、その参照は const 参照でなければなりません。 もともと const 属性はポインタにつけて、const 属性のついたポインタに -> 演算子を使って出来たメンバ変数の値を変更しないようにコンパイル時に厳密にチェックする縛りです c++ における参照は「機械的にポインタを使った書き方に書き直すこと」が可能(…A※)ですから、const なイテレータ(≒ポインタ)から生成した参照は const な参照にならざるを得ないのです ※Aは私の持論で、今回のお題でも参照をポインタに全部書き換えてやろうと試行錯誤していましたが、さすがに iostream や set で先に参照として宣言されているものを後からポインタにするのは不可能でした 頑張ってみたけれども、かえって意味不明な https://ideone.com/Yc0YvT ぐらいにしかならなかった、持論は修正しなくてはいけないなあ… set は重複要素を許さない二分木構造です。二分木構造 set に要素を挿入するときに、要素の大小関係にしたがって二分木の形をくみ上げていきます。 だからすでに二分木に組み込まれてしまった要素が、後からほいほいと要素の内容を変えられてしまっては二分木構造に矛盾をきたし、役に立たなくなってしまう… だから set にすでに組み込まれている要素をイテレータで走査するときは、そのイテレータ≒ポインタは、メンバの書き換えが不可能なイテレータとするしかないか、と私は考えます 提示していただいたソースを、上に述べた原則にしたがって、この原則に関係ない余分な部分を削り落として書く(あと、ちょっと簡略化もしています)と次のような感じでしょうか。 https://ideone.com/Zr1qIH friend 略 operator<<(略 C const &obj) { ... } にならなくてはならないのは set<C>::iterator は set<C>::const_iterator と同じだからです friend bool operator<(C const &a, C const &b) は set への要素の挿入のときに使う比較関数ですが、比較作業以外に要素のメンバを変えるとか余計なことをさせないために、最初から const 参照で宣言するべきでしょうし、そうなっているみたいですね しかし、この const 属性はプログラミング 3 年生くらいまでは、かなり分かりにくい縛りであることは、私の経験からもとても理解できます。 ポインタや参照をしっかり理解しないことには、わざわざ自分を縛る const のありがたみもよく理解できないだろうと、私も同情するのです。そういうときは、const_iterator p から作った表現 *p が展開された先の実際の表現を、「*p のコピー・オブジェクトのコピー」にするのがいいでしょう 上記のお題をこの方針で書くとこうなります。 https://ideone.com/G42gUs いろいろ書きすぎたかもしれませんが、上に示した三つのソースコードを研究してみてください
294 名前: mailto:sage [2021/06/06(日) 01:58:54.60 ID:xlnMgrm3.net] >>291 >>293 https://mevius.5ch.net/test/read.cgi/tech/1594615908/593 593 名前:◆QZaw55cn4c [] 投稿日:2021/03/14(日) 20:13:24.03 ID:uaeFGveg [3/6] >>590 >C++は未だ*や&、&&、で頭の中がグルグル回ってしまう これらの「記号」は習得に順序があります。 まず * をしっかり理解します。C/C++ はなんといってもポインタが基本です。 次に参照 & を理解します。参照& を使う場面が出てきたら、これを * を使った書き方に書き直す、という機械的な訓練がいい練習になるでしょう 参照 で返す、という場面でも、@参照返しが出来る場合と、A参照返しはできずせいぜい RVO に期待するしかない場合、の@A二つの違いを明確に即答できるようになるべきでしょう(最近まで私はそれができなかった……)参照& の表現は新しい表現( ranged-for とか) でよく目にしますし、@Aは結構重要だと思います && は多分最後でしょうね、私も && は良く分かっておらず、というか、分からないから使わないという態度に留まっていますが、まあそれでもなんとかなる気がします
295 名前: mailto:sage [2021/06/06(日) 02:07:24.75 ID:xlnMgrm3.net] >>292 operator<<() のストリームじゃないほうの引数は、const 参照ではなくてもいいと思います 今回のは const 参照が要求されたのは、 set のイテレータだから https://ideone.com/j6CV0s
296 名前: mailto:sage [2021/06/06(日) 02:32:48.87 ID:xlnMgrm3.net] >>293 ソースを貼り付けた一行目がミスっていましたね、修正します。 >しかし、この const 属性はプログラミング 3 年生くらいまでは、かなり分かりにくい縛りであることは、私の経験からもとても理解できます。 >ポインタや参照をしっかり理解しないことには、わざわざ自分を縛る const のありがたみもよく理解できないだろうと、私も同情するのです。 >そういうときは、const_iterator p から作った表現 *p が展開された先の実際の表現を、「*p のコピー・オブジェクトのコピー」にするのがいいでしょう >上記のお題をこの方針で書くとこうなります。 https://ideone.com/Ivx0JY
297 名前:デフォルトの名無しさん mailto:sage [2021/06/06(日) 02:41:34.70 ID:Lz5dZs8J.net] ああ、operator <<のconstも最初付いてなかったのか それならsetの仕様変更のせいだね というか昔のままの非constの方が良かったんだけどなぁ 比較演算子自分で書いてるような構造体だと順序変わらない場合もあるんだし・・正直押し付けがましい
298 名前: mailto:sage [2021/06/06(日) 03:22:16.34 ID:xlnMgrm3.net] >>297 自分で一から書く分には const に一貫性を持たせて、結果、const が有用に働くように書いていけるかもしれない、とか思うのですが、 他の人の分を取り込むときは、最悪 const_cast を >>291 の言うように「適当にconst_cast をつけていたらコンパイルできるようになりました」とか私も言っているわけでして、私は >>291 を笑うことができません……
299 名前:デフォルトの名無しさん mailto:sage [2021/06/06(日) 08:29:50.46 ID:KyPgEn9X.net] 一から書いている私ですが、 全てのフォルダ・ファイル・プログラムに一貫して *と何か名前を付けてプログラミングをしています。
300 名前:デフォルトの名無しさん mailto:sage [2021/06/06(日) 08:34:21.45 ID:8VTCuGWY.net] QZ・・・・ C++をちゃんと理解できてないのに無理すんなw
301 名前: mailto:sage [2021/06/06(日) 09:27:07.17 ID:xlnMgrm3.net] >>300 >C++をちゃんと理解できてないのに無理すんなw うん。すっごく認めます! でもちゃんと理解できていないからこそ、アウトプットもきちんと書くようにして定着させたい、というのもあるんですよ 「教えることは教わること」 >>291 に対する回答としての >>293 , >>295 に間違いはないですよね?
302 名前:デフォルトの名無しさん mailto:sage [2021/06/06(日) 09:44:11.48 ID:WkbXnMOk.net] 意味分からん理屈だな ずっと前からC++分からないって言ってるよね? もしかして理解できる頭を持ってないのかな?
303 名前: mailto:sage [2021/06/06(日) 13:37:50.42 ID:xlnMgrm3.net] >>302 自己申告なんて当てにしてはいけないのでは?
304 名前:デフォルトの名無しさん mailto:sage [2021/06/06(日) 15:27:30.95 ID:fMmzH2Jl.net] 文面から必死な感じがヒシヒシと伝わってくるのに 皮肉も理解できないとはさすが厚顔無恥の代表格 誰も認めてくれないから自画自賛するしかないんですね
305 名前: mailto:sage [2021/06/06(日) 16:22:05.09 ID:xlnMgrm3.net] >>304 え?必死?思いがけない反応ですね まあ >>291 の方が提示したソースはハーバードシルトにしては冗長だと思って無駄丁寧っぽく説明したほうがいいかと >>293 をワサワサ書きましたが、それが必死だとは… よく分かっている方 >>292 に対しては簡潔に私の意見 >>295 を送ってもう十分、仕様変更があったという情報 >>297 をいただいて感謝、というところでしょうか
306 名前:290 mailto:sage [2021/06/06(日) 22:29:30.82 ID:DvMt5hdj.net] >>292 >>293 どうもありがとうございます constメンバ関数の理解が不十分だったようです constメンバ関数はメンバ変数を変更しないという理解だけで、 constオブジェクトはconstメンバ関数しか呼べないことへの 理解が足りなかっため私自身混乱していました ご説明いただいた内容を足掛かりに理解を深めたいと思います
307 名前:1 mailto:sage [2021/06/07(月) 07:01:58.64 ID:pWKPTo4/.net] まぁ、いいじゃねぇか、プログラミングなんて何にも知らないってのスレだし。
308 名前:デフォルトの名無しさん mailto:sage [2021/06/07(月) 07:48:28.30 ID:c29T7zKX.net] const char* const str[] は文字列アドレスを格納するポインタの配列って意味であってますか? const char* strは文字列を格納するポインタ? char str[] は文字配列? 一気に出てきてよくわからなくなって来たので間違えてたら教えて欲しいです。
309 名前:デフォルトの名無しさん mailto:sage [2021/06/07(月) 08:39:52.02 ID:xFpLHEPr.net] >>308 だいたいあってる
310 名前:デフォルトの名無しさん mailto:sage [2021/06/07(月) 11:12:06.49 ID:BLDePS2Q.net] ちゃんとメモリ確保してから使えよ
311 名前:デフォルトの名無しさん mailto:sage [2021/06/07(月) 22:09:28.76 ID:JY7FyEcf.net] >>309 ありがとうございます。
312 名前:デフォルトの名無しさん mailto:sage [2021/06/08(火) 23:28:22.97 ID:kZSYpF+Y.net] https://ideone.com/2fyV5M 103 と115で確保された動的配列のアドレスは別物なんでしょうか? コピーコンストラクタの動きがよくわからないです
313 名前:デフォルトの名無しさん mailto:sage [2021/06/09(水) 02:24:41.44 ID:ZtayyY2i.net] 103のarrayはコピーされたものだから別物だよ てか初っ端から手直しが必要なソースを貼るのはやめろ
314 名前:デフォルトの名無しさん mailto:sage [2021/06/09(水) 02:39:16.49 ID:Ih94CWHU.net] スレの主旨的に初心者が初歩的な質問をするのは別に構わんとは思うんだが、 入門書にでも書いてあるようなことはよく読んで勉強したほうがいいと思うぞ。 素人が1レスで答えるよりはちゃんと体系だった解説のほうがわかりやすいよ、常識的に考えて。
315 名前:デフォルトの名無しさん mailto:age [2021/06/09(水) 04:24:03.76 ID:BGdtXEJj.net] >>313 すいません、ヘッダーとかcpp分けてるのどうアップロードすればいいのか分からなかったです 後65行目にcopy(other.m_array, other.m_array + m_size, m_array);とあるのですが何をしてるのか分かりません 本には”第1引数以上第2引数未満のアドレスにあるデータを第3引数の指すアドレス以降にコピーする関数で…とあるのですが 具体的に何をしてる関数なのでしょうか?第2引数の足し算も何なのかよく分かりません。
316 名前:デフォルトの名無しさん mailto:sage [2021/06/09(水) 04:43:32.09 ID:ZtayyY2i.net] https://ideone.com/EScxwq こうしたらそのままコンパイル通るやろ 自分のヘッダincludeしてるとこにヘッダの内容貼り付けるだけ https://cpprefjp.github.io/reference/algorithm/copy.html memcpyと似たようなもん(コピーの仕方は違うけど other.m_arrayの指すアドレスから+m_size分のアドレスまで(未満)をm_arrayの指すアドレスから同じく+m_size未満までコピーしとるだけ これで分からんならポインタの理解が出来てない 上記のとこだとイテレータとか出てるけどこの場合ポインタなので全部ポインタに読み替えていい
317 名前:デフォルトの名無しさん mailto:sage [2021/06/09(水) 04:53:28.23 ID:ZtayyY2i.net] ちょっと誤解招きそうなので補足 m_sizeは個数なのでアドレス値ではないがintのm_size個分アドレスが加算される このへんは>>314 の言う通り入門書嫁
318 名前:デフォルトの名無しさん [2021/06/09(水) 14:16:25.82 ID:3Qpbsqp/.net] cpp で socket を読み書きする stream 系の class ってありますか? boost にはあったと思いますが 標準のはあるんですか?無いですか?
319 名前:はちみつ餃子 mailto:sage [2021/06/09(水) 16:06:33.34 ID:Ih94CWHU.net] >>318 標準には無い。 が、ソケットに stream のインターフェイスをかぶせることはそれほど難しくはない。
320 名前:デフォルトの名無しさん mailto:age [2021/06/09(水) 22:30:15.61 ID:BwbEIJxn.net] >>316 1引数から2引数で足したアドレスまでを第三引数にコピーしてるのですね やっと分かりました。ありがとうございます。 頭硬い人はロベール向いてないのかな…
321 名前:デフォルトの名無しさん mailto:sage [2021/06/09(水) 23:57:13.88 ID:ZtayyY2i.net] それは良かった まぁ最初は理解に時間かかるもんだ
322 名前:デフォルトの名無しさん [2021/06/10(木) 10:45:51.80 ID:ZbfFyHii.net] >>319 thx cpp の std にある関数で glibc の様な getpass ってありますか? 標準のは無いですか?
323 名前:はちみつ餃子 mailto:sage [2021/06/10(木) 14:24:18.43 ID:MOYAWABe.net] >>322 無いよ。
324 名前:デフォルトの名無しさん [2021/06/11(金) 14:28:13.59 ID:tB3/M6ll.net] FILE *fp = fopen() で取得した fp を使って stringstream としてアクセスすることは出来ますか?
325 名前:はちみつ餃子 mailto:sage [2021/06/11(金) 17:27:01.32 ID:DsaVPusD.net] >>324 直接的に一発で FILE* に stream をかぶせる手軽な方法はないと思うけど、 std::basic_streambuf を継承して setbuf, overflow, sync などをオーバーライドしたクラスを作ればストリームバッファになる。 (普通は std::basic_filebuf も内部的にはそう実装されているはず。) それをストリームに結び付ければストリームに出来ることは何でもできるよ。 仕様を調べるのがすごくしんどいだろうけど、 実装は (細かいエラーチェックとかを抜きにすれば) 百行も要らないくらいの簡単なものでいけるんじゃないかな。
326 名前:デフォルトの名無しさん mailto:sage [2021/06/16(水) 00:59:39.17 ID:QFUk0bjY.net] >>324 fstreamを使えば? #include <fstream> #include <sstream> … std::ifstream fs("hoge.txt"); std::stringstream ss; ss << fs.rdbuf(); fs.close(); それともfstream使えない特殊な環境?
327 名前:デフォルトの名無しさん mailto:sage [2021/06/16(水) 16:36:23.72 ID:uJQ6HHCX.net] FILE *fp = fopen(...); std::ifstream fs(fp); 出来たらいいな
328 名前:デフォルトの名無しさん mailto:sage [2021/06/17(木) 21:31:03.90 ID:OB6uOiq6.net] 関数へ渡す引数の型を限定したいときどう書くのが一般的ですか? 具体的に言うと符号なしのintだけ受けつけたいんですけど
329 名前:はちみつ餃子 mailto:sage [2021/06/17(木) 23:54:09.39 ID:Gi/wqrqm.net] >>328 暗黙の型変換を許さないということかな? それならテンプレートにした上で型に制約を付ければいい。 ここでは C++11 でも通るように書いてみたけど C++20 以降なら コンセプトが使えるのでもう少し簡単に書ける。 #include <type_traits> template<class T> typename std::enable_if<std::is_same<T, unsigned int>::value>::type foo(T) { } int main(void) { int a = 1; unsigned int b = 2; foo(a); // これはエラーになる foo(b); // これは通る }
330 名前:デフォルトの名無しさん mailto:sage [2021/06/18(金) 08:42:03.67 ID:kejK9s3z.net] なんで戻り値voidに限定してんだよボケ餃子
331 名前:デフォルトの名無しさん mailto:sage [2021/06/18(金) 11:49:14.92 ID:AVf6Ht59.net] 確かにそれで可能だけど、回答が超初心者スレのレベルを逸脱していると思うのですが
332 名前:はちみつ餃子 mailto:sage [2021/06/18(金) 18:30:00.74 ID:JA4mPV9U.net] >>330 単なるサンプルだからだよ。 >>331 超初心者が相談するという主旨のスレではあるけど、 超初心者には理解できないという結果になることもあるだろうし、 可能であれば相談した結果として初心者から脱したらそれに越したことは無いでしょ。 これで相談がクローズってわけでもないから もっと深く知りたいってのならわからないところを続けて質問してもらってもいいわけで。 もっと簡単な方法があるならそれを提示するんだけども、なくなくなくない?