C++ の基本概念
C++ の基本概念 1
- Linux 3 の静的ライブラリと動的ライブラリの類似点と相違点
- 動的計画法を理解していますか 11
- STL ソースコードでのマップ実装 (赤黒ツリーの 5 つの要件) 12
B+ ツリー 13 - map と unorder_map (hash_map) の違い 14
- 新しいオブジェクトには何ステップが必要ですか? 新しい演算子をオーバーロードすることで変更できるステップはどれですか 15
- malloc は一度にどれくらいのメモリ空間を適用できますか? 16
- new と malloc 17 の違い
- 削除と解放の違い19
- いつ削除する必要があるか[] 20
- 静的ポリモーフィズム 動的ポリモーフィズム 21
- 動的バインディング (遅延バインディング、実行時バインディング)、静的バインディング (早期バインディング、コンパイル時バインディング) 21
- デザインパターンを学習しましたか? ステートマシンモード、シンプルファクトリー、ストラテジーモード、フライウェイトモード、テンプレートモード 1回24
- ポインターと参照の違い: 24
- C 言語コードのメモリ レイアウトの詳細 26
- メモリ内のヒープとスタックの違い 29
- ユーザープロセスメモリ空間 30
- 型変換とは何ですか? (4種類の変換、それぞれ例付き) 30
- メモリ調整の原則 33
- インライン関数(インライン関数の利点とマクロ定義との違いについての話) 35
- typedef と #define の使用法と違い 37
- const とマクロ定義の違い #define 39
- リンクディレクティブ: extern "C" 40
- 外部と含める 44
- 継承メカニズムでオブジェクト、参照、ポインタの間で変換する方法 45
- クラスオブジェクトのみを動的に割り当てることができ、クラスオブジェクトを定義することはできないことを理解する方法 46
- テンプレートの長所と短所 47
- テンプレートの特化 48
- 明示的な機能: プライマー P264 50
- strcpy 関数 53
- memcpy 55の欠陥
- メモリオーバーフロー、メモリリーク 56
- メモリリークをチェックするソフトウェアは何ですか 58
- 初期化リスト 59
- パブリック、プロテクト、プライベートのアクセス属性と継承 60
- スマートポインター61
- 仮想関数と純粋仮想関数 64
- コンストラクターを仮想関数にできないのはなぜですか。65 に使用される仮想デストラクターは何ですか?
- pthread_create()関数(Linux環境におけるスレッド作成関数)のプロトタイプを書き出す 66
- C 67 の volatile キーワード
- 親クラスのポインタはサブクラスを指すことができるのに、その逆はできないのはなぜですか?
- stlのリストのsize関数はどのように実装されていますか? それはトラバーサルですか、それとも保存する変数を設定していますか? 達成しましょう。どちらが好みですか、またその理由は何ですか? 69
- サブクラス a は b と c を複数継承しており、b と c の両方に仮想関数があります。a には仮想関数テーブルがいくつありますか? 仮想関数ポインタはいくつありますか? b と c に属する仮想関数が順番に呼び出されるとき、仮想関数ポインタはどのように変化しますか? 70
- 浅いコピーまたは深いコピー 72
- コピーコンストラクターと代入演算子の違い 76
- システム コールには sleep () 関数と usleep () 関数があります。usleep () 関数はマイクロ秒レベルであると主張していますが、実際にそれほど高速であると信じていますか? それともシステムコールはマイクロ秒の速度に達するのでしょうか? 77
- オーバーロード、オーバーライド、非表示 79
- this、const メンバー関数、可変型 80
- STL メモリ管理 81
- 静的グローバル変数と非静的グローバル変数の違い 83
- メイクファイルの書き込み 84
- コアダンプ 85 によって生成されるいくつかの考えられる状況
- ネットワーク接続における長いリンクと短いリンク。86
- 同期 IO と非同期 IO、ブロッキングとノンブロッキング 87
- スタックとキューの実装 89
- ビッグエンディアン リトルエンディアン 90
- コンパイラはどのような最適化を行いますか 92
- オブジェクトのメンバー関数をコールバックしますが、このオブジェクトはもう存在しない可能性があります。どうすればよいですか? 93
- C++11 の機能を紹介する 94
- ハードディスクコピー速度、メモリコピー速度 95
- Gdb デバッグ、コア ダンプ ファイルのデバッグ 96
- コンストラクターは仮想関数を呼び出すことができますか98
- Dynamic_cast が失敗するとどうなりますか? 100
- デストラクターが例外 101 をスローできないのはなぜですか
44. コピーコンストラクターと代入演算子の違い
コピーコンストラクターは、最初はコンストラクターであり、呼び出されるとオブジェクトを生成し、パラメーターとして渡されたオブジェクトによって初期化され、生成されたオブジェクトが生成されます。
Operator=(); は、元のオブジェクトにオブジェクト(オブジェクトはすでに存在します)を割り当てることなので、元のオブジェクトにメモリ割り当てがある場合は、最初にメモリを解放する必要があり、2 つのオブジェクトが存在するかどうかを確認する必要もあります。同じである場合、オブジェクトは何も行いません。
初期化されたカスタム クラス タイプ オブジェクトを使用して、新しく構築された別のオブジェクトを初期化する場合、コピー コンストラクターが自動的に呼び出されます。つまり、クラスのオブジェクトをコピーする必要がある場合、コピー コンストラクターが呼び出されます。コピー コンストラクターは、
オブジェクトが値によって関数本体に渡される場合、
オブジェクトが値によって関数から返される場合、および
オブジェクトを別のオブジェクトによって初期化する必要がある場合に呼び出されます。
既存のオブジェクトを使用して、存在しないオブジェクト (構築前には存在しなかった) を構築することは、コピー構築です。既存のオブジェクトを使用して別の既存のオブジェクトを上書きすることは、代入操作です。
ディープ コピーが必要な場合、プログラマは 2 つの関数を同時に明示的に定義する必要があります。
45. システムコールには sleep () 関数と usleep () 関数があります。usleep () 関数はマイクロ秒レベルであると主張していますが、本当にこの速度に達できると思いますか? それともシステムコールはマイクロ秒の速度に達するのでしょうか?
46. オーバーロード、オーバーライド、非表示
過負荷:
カバレッジ (仮想関数多態性の場合) は、基本クラス関数をカバーする派生クラス関数を指し、派生クラス関数にのみ適用されます。
非表示とは、派生関数が基底クラスの関数を隠すことを意味しますが、もちろん派生クラスの関数に対してのみ機能し、オーバーライドとは性質が異なります。
異なるクラスでは、オーバーロード条件が満たされる場合はカバーされ、仮想関数カバレッジ条件が満たされるが仮想がない場合も非表示になります。
同じ名前のパラメータが同じで仮想の場合、上書きされます。
47.this、constメンバ関数、可変型
1. オブジェクトが関数を呼び出すとき、内部で呼び出されたクラスのメンバーがどのオブジェクトに属しているかを区別するために、オブジェクトのポインタを渡して初期化して関数に渡します。仮パラメータ this はクラス オブジェクトへのポインタです。静的メンバー関数はクラスの不可欠な部分ですが、どのクラス オブジェクトにも属していないため、静的メンバー関数にはこのポインターがありません。仮想関数もこれを通じて呼び出されるため、静的メンバー関数を仮想関数にすることはできません。
2. デフォルトのメンバ関数の this の型はクラス型を指す const ポインタであり、ポインタ自体は変更できませんが、指す内容、つまりオブジェクトのアドレスは変更できませんが、オブジェクト内のメンバーは変更できます。関数の後に const を追加すると const メンバ関数となりますが、この型は const クラス型のオブジェクトを指す const ポインタであり、オブジェクトの内容は変更できません。(オブジェクトが間接的に変更される可能性があるため、非 const メンバー関数を呼び出すことはできません。)
3. const メンバー関数でオブジェクトのメンバーを変更する場合は、メンバーの前に mutable キーワードを追加する必要があります。メンバーが const メンバー関数内にある場合でも、変更することができます。
48. STL メモリ管理
alloc スペース割り当ての戦略
小さなブロックによって引き起こされる可能性のあるメモリの断片化の問題を考慮して、SGI は 2 層コンフィギュレータを設計しました。
コンフィギュレーション ブロックが 128 バイト (Bytes) を超える場合、そのブロックは十分大きいとみなされ、第 1 レベルのコンフィギュレータが呼び出されます。
対応するコンフィギュレーション ブロックが 128 バイトより小さい場合、小さすぎるとみなされ、第 2 レベルのコンフィギュレータが呼び出されます。
第 1 レベルのコンフィギュレータは malloc() と free() を直接使用し、メモリの断片化を軽減するために、第 2 レベルのコンフィギュレータは対応するメモリ プール方式を採用します。
第 2 レベル コンフィギュレータのメモリ プールの管理方法は次のとおりです。
(1) フリー リスト: 単一リンク リスト構造に似たデータ構造であり、リンク リスト内の各小さなブロックはユーザーによって使用されていません (使用されるのは、フリーリストによる接続の切断です)。管理の便宜のために、SGI 第 2 層コンフィギュレータは、小さなブロックのメモリ要件を 8 の倍数に積極的に増加させます (たとえば、7 バイトが必要な場合は、 8 バイトが与えられ、1 バイトの内部フラグメントがあります)、16 個の空きリストを維持し、それぞれがサイズ 8、16、24...128 バイトの小さなブロックを管理します。
(A) ユーザがシステムにデマンド(nbyteメモリ)を渡すと、システムはフリーリストの先頭配列からリンクリストに対応する先頭ポインタを見つけますが、そこに空き領域がない場合(先頭ポインタ)が空である場合)、メモリ プールに空きがない場合は、free-lis の残りのメモリに追加して見つけ、余分なスペースがない場合はヒープに適用します。
メモリ解放プロセス:メモリ
解放プロセスは比較的単純で、解放するメモリ ブロックを指すポインタ p と、解放するメモリ ブロックのサイズ n を示す 2 つのパラメータを受け取ります。解放されました。アロケータは最初に n を判断し、n>128 バイトの場合はそれを最初のアロケータに渡して処理し、そうでない場合はメモリ ブロックを対応するフリー リストに追加します。(無料リストはどんどん大きくなっていきます)
49. 静的グローバル変数と非静的グローバル変数の違い
1. 静的グローバル変数は、静的外部変数または静的グローバル変数と呼ばれます。
2. 非静的グローバル変数は、外部変数またはグローバル変数と呼ばれます。
3. 違いは、static で宣言された外部変数は、このファイル内の関数によってのみ呼び出すことができ、他のファイル内の関数によって呼び出すことはできないことです。
静的グローバル変数には次の特性があります:
• 変数はグローバル データ領域にメモリを割り当てます;
• 初期化されていない静的グローバル変数は、プログラムによって自動的に 0 に初期化されます (明示的に初期化されない限り、自動変数の値はランダムです)
。静的グローバル変数は、それが宣言されているファイル全体で参照できますが、その外部では参照できません。
50. メイクファイルを書く
51. コアダンプによって生成されるいくつかの考えられる状況
プログラムのコアダンプが発生する理由は数多くありますが、一般的な例をいくつか示します:
1. メモリ アクセスが範囲外である
a) 間違った添字の使用により、配列アクセスが範囲外である。
b) 文字列を検索するときは、文字列の終わりに基づいて文字列が終了しているかどうかを判断しますが、文字列は通常の文字の終わりを使用しません。
c) strcpy、strcat、sprintf、strcmp、strcasecmp およびその他の文字列操作関数を使用して、ターゲット文字列を読み取り/書き込みします。範囲外の読み取りおよび書き込みを防ぐために、strncpy、strlcpy、strncat、strlcat、snprintf、strncmp、strncasecmp などの関数を使用する必要があります。
2. マルチスレッドプログラムはスレッドアンセーフ関数を使用しています。
次のリエントラント関数を使用する必要がありますが、悪用されやすいです:
asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n)ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c)getservent_r (3n) fgetgrent_r (3c) getnetbyaddr_r(3n) getspent_r(3c)fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c)getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_ r(3m ) getauclassent_r( 3)getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n)nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3)getpwent_r(3c) readd ir_r(3c) getauevnum_r (3) ) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c)getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c)getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r( 3n) getrpcent_r (3n)
3. 複数のスレッドで読み書きされたデータはロックによって保護されません。
複数のスレッドによって同時にアクセスされるグローバル データの場合は、ロック保護に注意を払う必要があります。そうしないと、コアダンプが発生しやすくなります。
4. 不正なポインタ
a) ヌルポインタを使用する
b) 任意にポインタ変換を使用する。メモリの一部へのポインタ。このメモリの一部がもともと特定の構造体または型、またはこの構造体または型の配列として割り当てられたことが判明しない限り、それ以外の場合は、この構造体または型へのポインタに変換すべきではありません。ですが、このメモリ部分は、この型の構造体または型にコピーされ、その構造体または型にアクセスされます。このメモリの先頭アドレスがこの構造や種類に合わせて揃っていないと、アクセス時のバスエラーによりコアダンプが発生しやすくなるからです。
5. スタック オーバーフロー (終了条件なしで関数を繰り返し再帰的に呼び出す)
大きなローカル変数は使用しないでください (ローカル変数はすべてスタック上に割り当てられるため)。スタック オーバーフローが発生しやすく、システムのスタックとヒープ構造が破壊され、説明できないエラーが発生します。
52. ネットワーク接続における長いリンクと短いリンク。
HTTP1.1では、デフォルトで長時間の接続(HTTP永続接続、永続接続とも訳されます)を維持することが規定されており、データ送信完了後はTCP接続を切断せず(RSTパケットなし、4ウェイハンドシェイクなし)、同じドメイン名でこれを使用し続けるのを待ちます チャネルはデータを送信しますが、その逆は短い接続です。
53. 同期 IO と非同期 IO、ブロッキングとノンブロッキング
IO を処理する場合、ブロッキングと非ブロッキングの両方が同期 IO です。
特別な API を使用するだけが非同期 IO です。
「ブロッキング」と「ノンブロッキング」、「同期」と「非同期」は文字通りに単純に理解することはできず、分散システムの観点から答えが得られます。
1. 同期と非同期 同期
と非同期は、メッセージ通信の仕組み (同期通信/非同期通信) に焦点を当てており、
いわゆる同期とは、呼び出しを発行すると、結果が得られるまで呼び出しが返されないことを意味します。ただし、呼び出しが返されると、戻り値が返されます。
言い換えれば、この呼び出しの結果を積極的に待つかどうかは呼び出し側次第です。
非同期はその逆で、呼び出しが発行された後、呼び出しは直接返されるため、結果は返されません。つまり、非同期プロシージャ呼び出しが発行されても、呼び出し元は結果をすぐには取得しません。代わりに、呼び出しが発行された後、呼び出し先はステータスと通知を通じて呼び出し元に通知するか、コールバック関数を通じて呼び出しを処理します。
a. 実行コンポーネントが状態によって通知される場合、
呼び出し元は定期的にそれをチェックする必要がありますが、これは非常に非効率的です。
マルチスレッド プログラミングの初心者の中には、変数の値をチェックするために常にループを使用することを好む人もいます。実は非常に重大な間違いです。
b. 通知方法を使用する場合、
実行コンポーネントは追加の操作をほとんど必要としないため、効率が非常に高くなります。
c. コールバック関数に関しては、
通知と大きな違いはありません。
Node.js などの典型的な非同期プログラミング モデル
よくある例を挙げると:
書店のオーナーに電話して、「分散システム」という本を持っているかどうか尋ねると、それが同期通信メカニズムであれば、書店のオーナーは「ちょっと待ってください。確認させてください」と言って電話をかけ始めます。チェックを待って (5 秒かかる場合もあれば 1 日かかる場合もあります)、結果 (結果を返します) を教えてください。
非同期通信の仕組みとしては、本屋さんから「確認します」と直接言われ、確認後に電話をして直接(結果は返さずに)電話を切ります。それからそれを確認してください、そうすれば彼は率先してあなたに電話するでしょう。ここで上司は「コールバック」で電話をかけ直します。
- ブロッキングとノンブロッキング
ブロッキングとノンブロッキングは、呼び出し結果 (メッセージ、戻り値) を待つ間のプログラムのステータスに焦点を当てます。
ブロッキング呼び出しとは、呼び出しの結果が返される前に現在のスレッドが一時停止されることを意味します。呼び出し元のスレッドは、結果が得られるまで戻りません。
非ブロッキング呼び出しとは、結果がすぐに得られなくなるまで呼び出しが現在のスレッドをブロックしないことを意味します。
上記の例でも、
書店のオーナーに電話して、「分散システム」という本があるかどうかを尋ねます。ブロック電話をかけると、その本が入手可能かどうかの結果が得られるまで自分自身を「ぶら下げ」続けることになります。はノンブロッキング コールです。ボスが通知するかどうかは気にしません。まずプレイに行きます。もちろん、ボスが結果を返したかどうかを数分に 1 回チェックする必要があります。
ここで、ブロッキングとノンブロッキングは、同期か非同期かには関係ありません。上司があなたの結果にどう答えるかは関係ありません。
54. スタックとキューの実装
スタックは配列を使用して実装できます。
キュー。循環配列 (いっぱいになったら大きな配列を再割り当て) またはリンク リスト (オーバーフローしない) で実装されます。
55. ビッグエンディアン リトルエンディアン
ビッグエンディアン ハイエンディアン リトル
エンディアン スモールエンディアン
数値を文字列とみなした場合、たとえば 11223344 を "11223344" とすると、末尾は '\0' となり、'11' ~ '44' が記憶装置を占有し、その末尾がend は明らかに 44 です。先頭の high または low は、end が上位アドレスまたは下位アドレスに配置されることを意味します。以下の図に示すように、メモリ内での配置は非常に直感的です。
これら 2 つのバイト順序には標準がありません。、システムがあります。使用中です。特定のシステムで使用されるバイト オーダーはホスト バイト オーダーと呼ばれ、次のプログラムを使用してホスト バイト オーダーを出力できます。この方法では、2 バイト値 0x0102 を短整数変数に格納し、その連続バイト c[0] (上図のアドレス A に対応) と c1 をチェックしてバイト順序を決定します。
56. コンパイラはどのような最適化を行いますか?
57. オブジェクトのメンバー関数をコールバックしますが、このオブジェクトはもう存在しない可能性があります。どうすればよいですか?
A: スマート ポインターを使用します。
男性: スマート ポインタは何ですか?
A:shared_ptr。
M: では、その物体が存在しないことはどうやって分かるのですか?
A: わかりません。
M: これは今まで知らなかったweak_ptrの使い方(expired()がfalseなのか、use_count() > 0なのか)で、オブジェクトがまだ存在しているかどうかを判定することができます。
関数 non-f1 が f2 を呼び出すと、関数 f3 (コールバック関数) も f2 に渡され、f2 は適切な条件で f3 を呼び出して結果を返すことができます。
何かを買おうと店に行き、欲しい商品が在庫切れだったため、店員に電話番号を残し、数日後に店に在庫があり、店員から電話があり、その後、電話がかかってきて、お店に商品を取りに行きました。この例では、あなたの電話番号はコールバック関数と呼ばれ、登録コールバック関数を呼び出すために店員に通話を任せます。後で店舗に商品が到着すると、コールバックに関連付けられたイベントがトリガーされてコールバックが呼び出され、店員が電話をかけます。店舗に商品を取りに行くことをコールバック関数を呼び出すことをコールバックイベントに応答することといいます。
58. C++11の機能を紹介する
1.Auto
2.=default =delete
=default はデフォルトのコンストラクターを生成します。=delete はこの関数を宣言しますが、この関数を呼び出すことはできません。通常、コピー コンストラクターと = 演算子に使用され、その他のデストラクターにも使用できます。機能。
3.nullptr
4.for(auto n:v)
5.スマート ポインター:
unique_ptr、shared_ptr、weak_ptr
6.ラムダ式:
呼び出し可能なコード単位を表し、名前のないインライン関数として理解できます。
ローカル変数をキャプチャ リスト [] に含めることで、ローカル変数が使用されることを示すために関数内で使用できます。
通常の関数との最大の違いは、Lambda 関数はパラメータに加えて、キャプチャ リストを通じて一部のコンテキストのデータにアクセスできることです。
1. [var] は、値転送メソッドが変数 var をキャプチャすることを示します。
2. [=] は、値転送メソッドが親スコープ内のすべての変数 (これを含む) をキャプチャすることを示します。
3. [&var] は、参照転送メソッドが変数 var をキャプチャすることを示します。変数 var;
4. [&] は、参照転送メソッドが親スコープ内のすべての変数 (this を含む) をキャプチャすることを意味します;
5. [this] は、値転送メソッドが現在の this ポインタをキャプチャすることを意味します。
1.[=,&a,&b] は変数 a と b を参照によってキャプチャし、他のすべての変数を値によってキャプチャすることを意味します; 2.[&,a,this] は変数 a と this を値、つまりパスバイによってキャプチャすることを意味し
ます-reference メソッドは、他のすべての変数をキャプチャします。
ただし、キャプチャ リストでは変数を繰り返し渡すことができないことに注意してください。次の例は、コンパイル時エラーを引き起こす典型的な重複です。例:
3. ここの [=, a] は値転送によってすべての変数をキャプチャしましたが、a が繰り返しキャプチャされるとエラーが報告されます;
4. ここの [&,&this] & は参照転送によってすべての変数をキャプチャしました、そしてそれからこれを捉えるのも繰り返しです。
7. リストの初期化
8. 正規表現
9. 静的アサーション:
static_assert はコンパイル時のアサーション チェックを提供します。アサーションが正しい場合は、何も起こりません。アサーションが false の場合、コンパイラは特別なエラー メッセージを出力します。
59. ハードディスクコピー速度、メモリコピー速度
ハードディスクのアクセス速度が70~80MB/s
、メモリが1GB/sの方が速いのは間違いありませんが、どれくらい速いのでしょうか?
一般的に言われているのは、メモリのアクセス速度はナノ秒 (10 の -9 乗)、ハードディスクのアクセス速度はマイクロ秒 (10 の -3 乗) です。以下の図に示すように、少し科学的なテスト データを見つけてください。
メモリとハードディスクの速度を比較するには、2 つのタイプの比較があります:
1. シーケンシャル アクセス: この場合、メモリのアクセス速度はわずか 6 ~ 7 です。ハードディスクのアクセス速度の倍 (358.2M / 53.2M = 6.7)
2. ランダムアクセス: この場合、メモリのアクセス速度はハードディスクのアクセス速度 (36.7M / 316 = 113,924) の 100,000 倍以上高速です。
60. Gdb デバッグ、コア ダンプ ファイルのデバッグ
一般的な GDB 操作
上記のプログラムは比較的単純なので、追加の操作を行わなくても問題を直接見つけることができます。実際にはそうではなく、問題をスムーズに特定するには、シングルステップ追跡を実行し、ブレークポイントを設定する必要があることがよくあります。GDB で一般的に使用される操作の一部を以下に示します。
プログラムの開始: run
ブレークポイントの設定: b 行番号 | 関数名
ブレークポイントの削除: ブレークポイント番号の削除
ブレークポイントの無効化: ブレークポイント番号
の無効化 ブレークポイントの有効化: ブレークポイント番号の有効化
ステップ スルー: 次へ 省略することもできますn
シングルステップ追跡: step も省略可能 s
変数の出力: 変数名を出力
変数の設定: set var=value
変数の型の表示: ptype var
最後まで順次実行: cont
特定の行までの順次実行: util lineno
スタック情報を出力します。 bt
gdb+ファイル名で開始してデバッグを開始します。
bt コマンドは、特に関数の入れ子が深く呼び出し関係が複雑な場合に強くお勧めします。関数全体の呼び出しスタックを表示でき、呼び出し関係が一目瞭然です。さらに、上記の 2 つのシングルステップ コマンドがあり、1 つは n で、もう 1 つは s です。主な違いは、n は関数呼び出しをステップとして実行するのに対し、s は呼び出し関数内でフォローアップすることです。
bt によって表示されるスタック情報は、上記の次の呼び出しのスタック構造と同じです。
コア ダンプとは何ですか?
コアとはメモリを意味し、ダンプとはそれを吐き出す、または積み上げることを意味します。Unix プログラムを開発および使用していると、時々プログラムが不可解にダウンすることがありますが、プロンプトは表示されません (コア ダンプのプロンプトが表示される場合もあります)。時々、core.プロセス番号の形式のファイルがあるかどうかを確認できます。このファイルは、プログラムがダウンしてメモリの内容が破棄されたときにオペレーティング システムによって生成されます。このファイルは、プログラムのデバッグ コア ダンプはコア
転送とも呼ばれます プログラムの実行中に例外が発生し、プログラムが異常終了すると、オペレーティング システムはプログラムの現在のメモリ状態をコア ダンプと呼ばれるコア ファイルに保存します。
コア ファイルが生成されないのはなぜですか?
プログラムがダウンしているにもかかわらず、コア ファイルが生成されないことがあります。コア ファイルの生成は、現在のシステムの環境設定に関連しています。次のステートメントで設定できます。プログラムを実行してコア File.ulimit
-c unlimited
core を生成します。コア ファイルが生成される場所は通常、実行中のプログラムのパスと同じで、ファイル名は通常 core.process 番号です。
コア ファイルを取得した後、コマンド gdb を使用して検索できます。最初のパラメータはアプリケーションの名前で、2 番目のパラメータはコア ファイルです。例: gdb […]xmsd [
…]/xmsd_PID1065_SIG11.core
次に、「bt」または「where」と入力すると、エラーが発生した場所と対応するスタック情報が表示されます。エラーが発生したときの関数呼び出しの関係を知ることができ、上または下を使用して前後の項目の具体的な詳細を表示できます。このようにして、問題の大まかな位置を特定し、ソース コードを表示して分析できます。
コンストラクターは仮想関数を呼び出すことができますか?
構文は許容されますが、必要な出力は得られません。
蓄積されたコンストラクターを呼び出すときの出力は、オーバーライドされた関数ではありません。
実際の出力:
オブジェクトを構築するときのプロセスは次のとおりであることがわかります。1
) まず、オブジェクトのサイズに応じてメモリ (ヒープ上またはスタック上) が取得されます。2
) ポインタが指すこのメモリ部分へのポインタは、クラスのコンストラクタを呼び出してこのメモリを初期化するために使用されます。
3) オブジェクトに親クラスがある場合は、親クラスのコンストラクターが最初に (順番に再帰的に) 呼び出されます。親クラスが複数ある場合 (多重継承)、親クラスのコンストラクターが順番に呼び出されます。このポインタの位置が適切に調整されます。親クラスのすべてのコンストラクターを呼び出した後、独自のコードを実行します。
C++の標準仕様です。第 12.7.3 条には明確な規定があります。これは特殊なケースで、サブクラスの構築時に親クラスのコンストラクタが呼び出され、親クラスのコンストラクタ内で仮想メンバ関数が呼び出されます(仮想メンバ関数がサブクラスで書き換えられた場合でも)。 、ポリモーフィックな動作は許可されません。つまり、このときサブクラスで書き換えた仮想関数ではなく、親クラスの仮想関数を呼び出す必要があります。
これを行う理由は、親クラスのコンストラクターが呼び出されるときに、サブクラスのコンストラクター内のコードがまだ実行されていないため、サブクラス部分に属するオブジェクト内のメンバー変数が初期化されていてはいけないためです。この時点でポリモーフィックな動作が許可されている場合、つまり、サブクラスの仮想関数が親クラスのコンストラクターを通じて呼び出されると、この仮想関数がサブクラスに属するデータ メンバーにアクセスしようとしたときにエラーが発生する可能性があります。
同じ原則がデストラクターにも適用され、派生クラス デストラクターの実行が開始されると、オブジェクト内の派生クラスのメンバー変数の値は不定になるため、C++ はそれらの変数を存在しないかのように扱います。基本クラス デストラクターに入ると、オブジェクトは基本クラス オブジェクトになり、仮想関数、dynamic_cast などを含む C++ のすべての部分がそのように処理します。
基本クラスの構築中およびデストラクター呼び出し中に呼び出される仮想関数は、派生クラスに降下しません。詳細については、「Effective C++」の記事 9 を参照してください。
62.dynamic_cast 変換が失敗するとどうなりますか?
継承されたクラス ポインター ペア ポインターにキャストされた基本クラス オブジェクト ポインター (または参照) は
、NULL を返します。
参照のために、 bad_cast 例外がスローされます。
63. デストラクターはなぜ例外をスローできないのですか?
より効果的な C++ では、次の 2 つの理由 (デストラクターが例外をスローできない理由) を挙げています。
1) デストラクターが例外をスローした場合、デストラクターが例外ポイントの後に何かを実行する場合、例外ポイント以降のプログラムは実行されません。特定のリソースの解放などのアクションが実行されなくなり、リソース リークなどの問題が発生します。
2) 通常、例外が発生すると、C++ のメカニズムは構築されたオブジェクトのデストラクターを呼び出してリソースを解放しますが、このとき、デストラクター自体も例外をスローすると、前の例外が処理されずに新しい例外が発生します。 、プログラムクラッシュの問題が発生します。
C++ 例外処理モデルは、例外により無効になったオブジェクト (つまり、オブジェクトが元のスコープを超えた) をクリアし、オブジェクトによって最初に割り当てられたリソースを解放します。つまり、これらのオブジェクトのデストラクターを呼び出します。リソースを解放するタスクを完了するため、この意味で、デストラクターは例外処理の一部になります。
C++ 例外処理モデルに関する上記の説明には、実際には、デストラクターで例外がスローされるべきではないという前提があります。想像してみてください。オブジェクトで例外が発生した場合、システム オブジェクト データの一貫性を維持し、リソースの漏洩を避けるために、例外処理モジュールがオブジェクトのリソースを解放し、オブジェクトのデストラクターを呼び出す必要があります。このオブジェクトのリソース解放は誰が保証しますか? そして、この新しい例外は誰が処理しますか? 前の例外がまだ処理されていないため、これは矛盾、または無限再帰的ネストに陥っていることを忘れないでください。
3.2 では、デストラクターで例外が発生しないことを保証できない場合はどうすればよいでしょうか?
実際、それを解決する良い方法はまだあります。つまり、例外をデストラクター内に完全にカプセル化し、関数から例外をスローしないようにします (または、スマート ポインターを使用して、使用されているリソースを元のオブジェクトとして処理します)。これは非常にシンプルで非常に効果的な方法です。
~ClassName()
{ try{ do_something(); } catch(){ //ここでは何もできませんが、catch ブロック内のプログラムによってスローされた例外がデストラクターからスローされないことを確認するだけです。} }