C++オブジェクトモデルの6---実行期語意学を深く探求する

3716 ワード

C++オブジェクトモデルの6-実行期の意味学を深く探求する
C++の最も困難な点は,プログラムソースコードからプログラム式の複雑さを見ることができないことである.コンパイラは後ろでたくさんの仕事をしてくれるからです.T a = b +cのようないくつかの式では、コンパイラは実行期間中に一時オブジェクトを作成する可能性があり、プログラムの出口でコンパイラは、作成された一時オブジェクトが有効に構成されることを保証するために必要なコードを挿入する必要があります.goto、switchなどに遭遇すると複数の論理出口が発生する場合は、各出口にコードを挿入します.したがって、一般的には、objectの定義を使用するプログラムセグメントの近くにできるだけ配置し、不要なオブジェクトの生成と破棄操作を低減します.
実は上の点はC++に反映されて、私たちは関数の内部の任意の場所で変数を定義することができますが、Cプログラマーは慣れていて、関数の最初にすべての変数を定義するしかありません.
グローバルオブジェクト
c++プログラム内のglobal objectsはすべてプログラムのdata segmentに配置される.コンパイル時にclass objectコンテンツは0ですが、constructorはプログラムがアクティブになるまでトリガーされません.したがって、objectを静的に初期化する必要があります.
また,プラットフォーム間移植性の問題を考慮してmunch戦略が現れた.
  • 静的初期化が必要なファイルごとに1つの_を生成するsti()関数は、必要なconstructor呼び出しまたはinline expansionsを内蔵します.
  • 静的メモリの解放を必要とする動作ごとに生成される_std()関数は、必要なdestructor呼び出し操作またはinline expansionsを内蔵します.
  • main関数で_を生成main()と1つの_exit()関数、そのうち_main()は、実行前に生成されたすべての_sti()関数、そして_exit()は、実行前に生成されたすべての_std()関数.

  • 具体的には次の図のようになります.
    上記のコンパイラは、1つのプログラムのすべてを収集する方法です.sti()と_std()のは?ここでは紹介しない(メーカーごとにコンパイラの実現方法が異なる)
    ローカル静的オブジェクト
    ローカル静的オブジェクトについては、constructorとdestructorが一度しか実行できないことを保証する必要があります!!!
    new演算子とdelete演算子
    次のコードについて
    int *pi = new int(5)

    実際には、2つのステップに分けて完了します.
  • 関数ライブラリを呼び出す_new(int size)は、必要なメモリ
  • を割り当てる.
  • は、構成されたオブジェクトに初期値を設定するか、classのconstructor操作を呼び出すか、これらは、割り当て空間が成功した後に
  • を行う必要がある.
    new演算子のことですが、delete演算子はメモリスペースを解放する操作をします.
  • 検出ポインタが0
  • であるか否かを検出する.
  • ポインタが0でない場合、ポインタが指すメモリ領域
  • を解放する.deleteおよびdelete []の場合、配列のメモリ領域を解放するには後者を使用する必要があり、前者であればコンパイラは最初の要素を解放すると考えられます.以前はdelete []を呼び出すときにコード設計者が要素の個数を自分で指定する必要があったが、コンパイラは自分で検索することができ、プログラマが手動で要素の個数を指定してもコンパイラに無視されるようになった.
    コンパイラは配列の先端に追加のwordを追加し、要素の書目をこのwordに保存することでdeleteに達したときに要素の個数を決定します.
    もう1つ注意したいのは、base classのポインタを使用してderived classの配列を指す場合、delete []を呼び出すと問題があります.deleteはbase classのサイズに従ってメモリを解放するので、ポインタタイプを強制的にderived classタイプに変換することで、配列全体を反復するしかありません.次のようになります.
    Point *ptr = new Point3d[10]
    
    //       Point       ,       
    delete []ptr;
    
    //     
    for(int ix=0; ix < elem_count; ++ix) {
        Point3d *p = &((Point3d*)ptr)[ix];
        delete p;
    }

    Placement Operate newの意味
    あらかじめ定義されたリロードされたnew演算子がplacement operator newとなり、void*の2番目のパラメータが必要です.
    Point2w *ptw = new(arena) Point2w;

    arenaはメモリ内のスペースを指します
    Placement operator newは、必要なスペースを割り当てるために使用されますが、関連オブジェクトのコンストラクション関数は呼び出されません.したがってplacement operator newはobjectsがどこに置かれるかを決定するために使用することができる.
    次のコードを考慮します.
    void foobar() {
        Point2w *p2w = new(arena) Point2w;
        //do it...
        p2w = new(arena) Point2w;
    }

    上記のコードは、既存のobject上に新しいobjectを構築すると、class objectにdestructorがあっても、destructorは呼び出されません.
    一時オブジェクト
    完全な式の評価中に一時的なオブジェクトが生成される可能性があります.これにより、一時的なオブジェクトが破壊され、必要に応じて完全な式の最後のステップでメモリ領域の値が使用されないことが保証されます.それ以外の場合、一時的なオブジェクトは破壊されて解放されますが、コンテンツはアクセスされ、定義されていないエラーが発生します.
    一時オブジェクトがreferenceにバインドされている場合、オブジェクトは初期化されたrefeneceのライフが終了するまで、または一時オブジェクトのライフカテゴリが終了するまで残ります.