【初心者歓迎】C/C++室 Ver.104【環境依存OK】
■ このスレッドは過去ログ倉庫に格納されています
エスケープシーケンスやWin32APIなどの環境依存なものもOK
そのような質問は必ず環境を書きましょう
半角空白やタブでのインデントはスレに貼ると無くなります
コードを貼れる所
http://codepad.org/
https://ideone.com/
前スレ
【初心者歓迎】C/C++室 Ver.103【環境依存OK】
https://mevius.5ch.net/test/read.cgi/tech/1530384293/ >>441
正しくは、次のようにアクセス制御のための「public :」を書かないといけない。
class CMyClass {
protected :
BYTE *m_pBuf; // 高速化のため、自動的には初期化はされないのでコンストラクタで初期化する。
public :
CMyClass() { // コンストラクタ
m_pBuf = NULL; // メモリをまだ未割り当てであることをマークするためにこうしておく
}
~CMyClass() { // デストラクタ
if ( m_pBuf != NULL ) {
delete [] m_pBuf; // メモリの解放
}
}
}
なお、必要に応じて、コンストラクタの中で、m_pBuf = new BYTE [xxx]; のように書いても良い。
それと、BYTE は、「オブジェクト」ではないので、あなたの書いているような場合には、
BYTE *m_pBuf の部分を CSomeObject m_pObj; のように変えて、m_pObj = new CSomeObject;
のようにする。 良い子のみんなは>>441の危険性が理解できるまではスマートポインタを使ってね
おじさんとのお約束だよ >>445のデストラクタでnullチェック必要?
nullポインタをdeleteしても問題ないはずだが
二重解放防止にはならんし意味わからん >>448
超独自仕様の組み込み開発とか、メモリー管理がbuggyなプログラムでは意味があるらしい。
例えば解放したメモリーブロックをアクセスするような行儀の悪いプログラムでは意味がある。 >>441 >>445
・ 初期化を初期化リストでやらずに代入でやるのは邪悪。
・ delete に NULL を渡した場合には何もしないことが保証されているので、
無駄にヌルチェックする必要はない。
・ ポインタ型や整数型の値もまたそういう型の「オブジェクト」である。
(元質問者が Java から入ってきてるから「Java の用語で言うところの」という意味?) 初心者なので確認
コンストラクタの中に飛び込む前のメンバの初期化で例外発生したら m_pBuf は中途半端になるから
コンストラクタの中で代入するんじゃなく、メンバ初期化子で初期化しろ
という認識でいいのかしら >>451
「C++ 例外安全」でググれ。ナマポを使わずに、素直に生配列、コンテナ、スマポのどれかを使えば済むこと。マネージされてないナマポは村八分にしろ。 なんとなくわかった ような気がする
生ポそのものはコンストラクタもデストラクタに何ら操作しないから宙ぶらりんこになるのか ちょっち理解は大変だけど生ポはスマポにドンドン置き換えたい スマポならコピーコンストラクター・代入のややこしさからも解放される。 まあまあ。
スマートポインタを活用しろというのはその通りだが、
ポインタ (や例外機構) を理解せずに
思考停止してスマートポインタを使うのはあかんやろ。
ここの元質問者はまだそこを理解しようとしている
ところなんだから、スマートポインタを使わなかった場合にどう書けば良いのか、
きちんと書くと面倒くさすぎるという体験も必要だろ。 所有権の管理は人類には早すぎる。
所有権が変動するときは、スマポでOK. こんなときはナマポを使ってもよい:
処理の中で所有権が移動・消滅しない場合。
バイナリーデータやPODを生で扱う場合。
処理系がナマポやトークンやハンドルの入力を要求する場合。 生ポはスマポのオーバーヘッドすら許容できないときに使うものです
だから初心者は無理して生ポを使わなくていいです >>434
スマポは後になって導入されたもので人気がない、なんて意見は一般的ではないので無視して良い エアプwwwwwwwww今は参照カウントじゃねーよw残念だったなクソ蟻wwww それで、Cの生ポってC/C++以外で表現するなら何なんだ? >>464
仮装アドレス的な意味で来るとは思ってなかったwでも本質はそうだよなあ >>463 今の言語は極力「生のポインタ」が見えないようにしてるからなぁ。
オレの乏しい知識で無理矢理ヒネリ出すなら、
「古いBASICの peek, poke のアドレス指定に変数を使った場合」かのう。
型のない単なるアドレスって言うか数値だけど。 >>463
BYTE ptr = アドレス値;
BYTE MEM[4096 * 1024]; // 4GB のメモリ配列
*ptr ---> MEM[ptr] // ptr は MEM[] 配列の添え字 訂正:
BYTE MEM[4096 * 1024 * 1024]; // 4GB のメモリ配列 行儀よく バッファなんて 守れやしなかった
夜のサーバ オーバフロー起こしてまわった
*印見て アナルといわれた 早く添え字になりたかった
信じられぬ カーニハンとの 争いの中で
許しあい いったい何 解りあえただろう
うんざりしながら それでも過ごした ひとつだけ解ってたこと
このポインタからの 卒業 まあstatic変数やglobal変数使ってリークしてないとか言い張るバカよりかは
ナマポ使えやとは思う。
それならまだコード修正効くからな。
初心者にスマポ使わせればリークしないコード書かせることができるって考えははっきりいって幻想だわ。 昔研究室の後輩でポインタがわからないから全部グローバル変数でプログラム作ってるって奴がいて、
それはそれである意味すごいなって思ったわ。
マルチメディア系ライブラリを触る必要がある研究室なのだが。
元々組込系が得意な奴だったってのもあると思うけど。 >>476
スマートポインタを使うとコード修正効かなくなるの?どういうこと? mp4boxをちょこっといじったのを作ろうとしたんだけど、
signed int32の計算で -2112000 / 48000 の結果が 89434 になるんですが。
VS2015のx64です。 >>481 「-2112000 / 48000 の結果が 89434」
その環境を持ってないんで分からないけど、
-2112000 の32bit16進数表現が 0xffdfc600
89434 * 48000 == 4292832000.000 == 0xffdf6b00
両者のビットパターンが一致することと関係ありそうね。
被除数の -2112000 を64bitで表現する際に
符号拡張 0x_ffff_ffff_ffdf_c600 とすべきなのに
ゼロ拡張 0x_0000_0000_ffdf_c600 にしちゃって、
その後の計算は64bit正数でやってる感じかな。 >>480
本人がスマポ理解できてないってオチだろ >>477
組み込みが得意でポインタがわからない後輩
設定に無理がありすぎw 再び >>481 「-2112000 / 48000 の結果が 89434」 (間違いを訂正)
-2112000 の32bit16進数表現が 0xffdfc600
89434 * 48000 == 4292832000.000 == 0xffdf6b00
ビットパターン一致してないね。桁数多くて見間違えちゃった(テヘペロ)。
-2112000 を32bitで表現すると 0xffdfc600 であり、
これをゼロ拡張した 0x_0000_0000_ffdf_fc600 == 4292855330 を
48000 で割り算して小数部を捨てれば 89434 という答えが出る。
ということなら合ってるかな。 >>481
どうせ48000がunsignedなんじゃねーの
それにつられて -2112000もunsignedになって4292855296
その結果が薬師美代ちゃん >>479
自分が何してるか判って使う分には問題無いな
適材適所だ >>480
>スマートポインタを使うとコード修正効かなくなる
どういう風に読むとそういう理解になるのか。。
まずは日本語の理解が必要だな。 超初歩的な質問になるのですが
scanf関数を使って20個未満の任意の数だけ、数値を配列変数で受け取りたいです
たとえば「2 4 8 9」と入力し、Enterが押されたらそれで確定
num[0]=2
num[1]=4
num[2]=8
num[3]=9
としたいわけです。
どうしたらよいでしょうか?
一応自分で考えたコード(期待通りの動きをしません)を掲載します
for(i=0;i<20;i++){
scanf("%d",&num[i]);
if(num[i]==‘¥n’){
break;
}
} for(i=0;i<20;i++) if (scanf("%d",&num[i]) != 1) break; >>490
scanfや標準ライブラリの関数など、参考書とかで普通の使い方はわかると思うけど、細かい仕様をmsdnやmanコマンドで調べるようにするとかなり理解が広がると思うよ。 中途半端なUI使うよりもcsvパーサーを作るかどっかからとってくるかすれば? >>494
むしろ遅くなる方に振れるでしょうけれど、そんなのどうでもいいのでは? autoって変数の型宣言の話だよね?
コンパイルは遅くなるのか
速くしたい時はどうすりゃ良いの? C++ の auto は右辺と一致させるように推論するだけの単純機構で、
ややこしい演算で推論するわけではないので、
コンパイル速度ではほとんど差はないと思うよ。 autoはむしろコンパイル速くなるんじゃない?
いちいち型を解決せずとも、既に解決済みの型を右から左へコピーするだけでいいんだから
C++でコンパイルを速くするのは簡単で、単純にソースファイル数とインクルードするヘッダを減らせばいい
C++のコンパイルが遅いのは主にコンパイル単位という時代遅れで極めて非効率なコンパイル戦略に起因しており、実はコードの複雑さ自体はわりとどうでもいい >>496
C++を言語として選択した時点で「記述の時間やコンパイル時間を投資して実行時間を稼ぐ」という思想なのでは?コンパイル時間を短くする努力はする気がないと思います >>498
>いちいち型を解決せずとも、既に解決済みの型を右から左へコピーするだけ
この記述はコンパイル時を想定しているの?それとも実行時を想定しているの?
はっきりさせたいので念のために確認します >>490 サーバーの 503 エラーに引っかかって昨日のうちに書けなかったんだが…。
>>491 の方法だと Enter が単純に読み捨てられて scanf() が終了せず
まだ入力をよこせと言ってくるからダメみたいね。
11 22 33 (Enter) だと読み込みが継続、期待通りに動作しない
11 22 33 x (Enter) なら x を解釈する時点で scanf() が 0 を返してループ脱出
先に文字列として1行読み込んで sscanf() と思ったけど…
ndat = sscanf(s, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
&num[0], &num[1], &num[2], &num[3], &num[4], &num[5], &num[6], &num[7], &num[8], &num[9],
&num[10], &num[11], &num[12], &num[13], &num[14], &num[15], &num[16], &num[17], &num[18], &num[19]);
実際に読めた値の個数は ndat に入る。
これは書くのもメンテナンスするのも嫌だなぁ。
strtol() で1個ずつ数値を拾いつつ、地道にポインタ進める方が良いかも。 >>500 自分は >>498 の人じゃないけど。
ごく簡単な場合ながら、例えば
int val_a = func(para); // func() がint互換の値を返すかチェックが必要
auto val_b = func(para); // func() の返す型そのまんまで val_b を作ればいい
てな具合に考えると auto で定義した方がコンパイル時の手間が少ない、
という考え方にも一理あるかと。 瑣末なことだけど val_a, val_b って変数名は良くなかったね。
変数 variable の例なんだから var_a, var_b だわな。
というか、この場合は a, b で十分だ。 >>501
ありがとう。ちゃんと確認してなかったわ。
タブに空白に改行はスキップしやがるんでしたか
別案としては fgets() ⇒ sscanf() になるんかな 505の後半は無しで
1文字ずつ切り出して解析してったほうがよさそうね >>501
scanf は禁止
>>505 が正しい 人間の様な邪悪なものからの入力でscanfは使うなと、ばっちゃは言ってた >>502
>func() の返す型そのまんまで val_b を作ればいい
この発想は実行時なのでは?
>てな具合に考えると auto で定義した方がコンパイル時の手間が少ない、
実行時の発想をコンパイル時に適用していいのでしょうか? >>509
賛成です、そういうのは1ラインを秘術を尽くして何とか読み込み、後で sscanf() とかを使うべき >>512
今回の例(>>490) のように可能な限り %d で抜き出して打ち切るとなると sscanf 単発では面倒
なんとか行単位でバッファに詰めた後
連続空白などでトークンに区切ってそのトークン単位で sscanf をぶんまわすような
ほのかな中途半端感が >>510
別に実行時の発想じゃないでしょ
型を書けばコンパイラはその型名に対応する型を解決しなければならないし、
型変換の要否や可否のチェックも必要 >>514
>型変換の要否や可否のチェック
これは10中8, 9 コンパイル時にすることなのでは? >>515
初めからずっとコンパイル時間の話をしている。お前さんだけ噛み合ってないから、もう黙っててくれ。 C++です
インクルードガードがあっても関数の定義がヘッダに書かれていればヘッダが複数回読み込まれていた場合リンク時に多重インクルードでエラーが出る
ここまではわかるのですが、同じことをクラス関数で実験した結果エラーになりませんでした
具体的にはヘッダのクラス内に関数定義を書いて複数のファイルからインクルードしました
これはどういうことなのでしょうか? >>517
クラス定義の中に書かれたメンバ関数の定義は
自動的にインライン関数になる(関数の実体の定義ではない)
この場合は、複数の場所にメンバ関数の実体が作られるわけじゃない、
という説明でどうかな。 >>516
そもそも「実行時」「コンパイル時」の区別がついていないのでは、コンパイル時間の話なんかできないのでは?
だから「実行時」「コンパイル時」どちらを適用するかに執着しているだけです >>518
なるほど
クラス内に定義を書くとインライン関数になって普通の関数としては扱われないんですね
もう少し理解するために調べたのですが、インライン関数は内部リンケージのみを持つものとしてコンパイラに解釈されるらしいですね
だからコンパイラはファイル間での関数の重複を調べようとしない
そしてインクルードによって複数のファイルで同じものを読み込んだとしてもエラーにはならないと・・・
理解です
勉強になりました
ありがとうございました 失礼、なぜか >>510 を見逃してて(黙殺するような意図はまったくなかった)。
C++ は関数を宣言・定義するときに返り値型を書くから
auto で受けてもコンパイル時に曖昧さは生じないと考えたんだけど。
実行時まで返り値の型が決まらない関数って作れるんだっけ?
これは純粋に質問、教えを乞いたい。
あんまり高度な話だと振り落とされるかも知れないけど。 型推論が実行時に行われるとかトンチキこいてるやつが一人騒いでるだけ >>521
おそらく君の書いた「func()の返す型〜」をqz某が勝手に勘違いしているだけだからスルーしていいよ。
初心者が必ずしも正確な用語を使わないことくらい想像つくだろうし、文脈からして普通ならそんな勘違いはしないはずなのだが。 >>521
出来ない。
強いて言えば C++17 からは std::any があるけれど、
これはこれで実行時に型が決まるわけではなくて
コンパイル時に std::any 型であることは確定する。 >>520
> もう少し理解するために調べたのですが、インライン関数は内部リンケージのみを持つものとしてコンパイラに解釈されるらしいですね
どこにそんな嘘書いてあった?
https://timsong-cpp.github.io/cppwp/n4659/dcl.inline#footnote-94
> The inline keyword has no effect on the linkage of a function. >>525
IBMのサイトに書いてありました・・・
と思って今見返したらこれはIBMの統合開発環境のページなのでその開発環境の仕様かもしれないですね
失礼しました
https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_72/rzarg/inline_linkage.htm
>インライン関数は内部リンケージを持っているものとして処理されるので >>526
「C のみの始まり」〜「C のみの終わり」で囲まれているとおり、それはCの仕様だね。 >>525
それは inline キーワードで束縛された関数は、inline 展開される多数の実体と、外部リンケージによって外部からコールできるものとで別の実体をコンパイラは作成する、ってことですか
まあ inline しまくって無駄にバイナリーを増やすくらいだったら、ついでに1 個の外部リンケージで呼べる実体を追加したって、いろいろな面で大差がない、とはいえますね >>528
「それ」が何を指して言ってるのかよくわかんないけど、 inline 関数に対して
インライン展開されてない「実体」を生成するのもしないのもコンパイラの自由。
外部リンケージを持つ関数について複数のコンパイル単位でアドレスを取って
==, != で比較した場合には一致させないといけないので、アドレスを取られた場合には
そういうコード生成をするのが一般的だろうとは思う。 引数や関数にはconstつけられるところは全部つけるべきですか? つけて問題ないならつけるべきだけど、まあ実際は面倒くさくなければという程度… >>530
内部で書き換えないポインタや参照の引数には必ずconstをつけるべき。より自己文書化されるし、付けてないと使う側の手間が増える。>>531は元javaプログラマ 今は良いけど、半年後の自分は既に他人だと思わないと 530みたいな質問する奴はそもそもconst気にする前に関数が長すぎたり
参照と実値渡しの違いもわかってないと思われるのでその辺をしっかりやった方が良い。 入門書の類が、最初のうちは const なしで説明しておいて、
本の後半でおもむろにポインタの引数に const つけることを
載せてたりするせいかもな。
高度な、マニアックな話題みたいな感じで。
文字列(charへのポインタ)を受け取る関数を紹介したら、
すかさず const char* の説明も合わせてすべきって気がする。
const の一般的な価値が分かれば、メンバ関数での func() const {...} の
ありがた味もすぐ飲み込めて const つけまくり派になるでしょ。 戻り値を const char* してても、
char* const してなければさほど意味がない。 クソミソみたいなjavaのconstと違ってC++のconstは
コードの安全性を高めるのに必須といっていいぐらいのキーワード
とりあえず片っぱしから全部const付けて、どう頑張ってもここは
constはずさないと動くコードにできないよな・・ていうぐらいの
時だけはずす。このぐらいの気構えでコードを書けば、かなり安全な
コードになってる。他のやつが書きかえちゃダメなものをいじろうと
しても、強引なキャストでもしない限りどうやってもコンパイルが
通らなくなる。強引なキャストしてでも無理矢理強姦してくる強姦魔は
そもそも犯罪者気質なのでそんなやつに仕事をやらせてる時点で間違い 「かなり安全な」
ここで思わず笑ってしまったではないか 残念ながらバカはmutable使い出すから無意味。 俺は書換られたりはしない たぶんしないと思う
しないんじゃないかな ま、ちょっと覚悟はしておけ ■ このスレッドは過去ログ倉庫に格納されています