【C++】外伝編3_ダイナミックメモリ申請の結果

7891 ワード

ダイナミックメモリの結果
質問:ダイナミックメモリの申請は必ず成功しますか?
  • 一般的なダイナミックメモリ割り当てコード
  • Cコード:
    void code()
    {
        int* p = (int*)malloc(10 * sizeof(int));
        
        if( p != NULL )
        {
            // ...
        }
        
        free(p);
    }

    C++コード:
    void code()
    {
        int* p = new int[10];
        
        if( p != NULL )
        {
            // ...
        }
        
        delete p;
    }
  • 知っておくべき事実
  • malloc関数申請に失敗した場合NULL値
  • を返す
  • newキーワード申請に失敗した場合(コンパイラによって異なります)
  • NULL値(古代)
  • を返します.
  • std::bad_alloc異常(現代)


  • 質問:new文の異常はどのように投げ出されたのでしょうか.
  • newキーワードのC++仕様における標準動作
  • スタックスペースで十分なメモリを申請
  • 成功:
  • 取得空間でコンストラクタ作成オブジェクト
  • を呼び出す.
  • は、オブジェクトのアドレス
  • を返す.
  • 失敗
  • std::bad_alloc異常


  • newキーワードのC++仕様における標準動作
  • newメモリ割り当て時
  • スペースが不足している場合は、グローバルなnew_が呼び出されます.handler()関数
  • new_handler()関数からstd::bad_alloc異常
  • はnew_をカスタマイズできますhandler()関数
  • デフォルトのnewメモリ割り当ての処理に失敗した場合


  • new_handler()では、メモリの整理を手動で行うことができ、より多くのスタックスペースを使用することができます.
  • new_handler()関数の置換
  • は、戻り値なしパラメータなしの関数
  • をカスタマイズする.
  • 呼び出しset_new_handler()カスタム関数の設定
  • パラメータタイプvoid(*)()
  • 戻り値がデフォルトのnew_handler()関数エントリアドレス

  • new_handler()の定義と使用
  • void my_new_handler()
    {
        cout << "No enough memory" << endl;
    }
    
    int main(int argc, char* argv[])
    {
        set_new_handler(my_new_handler);
        
        // ...
        
        return 0;
    }

    プログラミング実験:new_handlerプローブ
    共通の実験コード:
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    class Test
    {
    private:
        int m_value;
        
    public:
        Test()
        {
            cout << "Test()" << endl;
            
            m_value = 0;
        }
        
        ~Test()
        {
            cout << "~Test()" << endl;
        }
        
        void* operator new (unsigned int size)
        {
            cout << "operator new: " << size << endl;
            
            // return malloc(size);
            
            return NULL;        //     !         
        }
        
        void operator delete(void* p) 
        {
            cout << "operator delete: " << p << endl;
            
            free(p);
        }
        
        void* operator new[] (unsigned int size)
        {
            cout << "operator new[]: " << size << endl;
            
            // return malloc(size);
            
            return NULL;        //     !         
        }
        
        void operator delete[](void* p) 
        {
            cout << "operator delete[]: " << p << endl;
            
            free(p);
        }
    };

    実験1:異なるコンパイラにおけるnew_handler()動作
    void my_new_handler()
    {
        cout << "void my_new_handler()" << endl;
    }
    
    void ex_func_1()
    {
        new_handler func = set_new_handler(my_new_handler);  //     !
        
        try
        {
            cout << "func = " << func << endl;
            
            if( func )
            {
                func();
            }
        }
        catch(const bad_alloc&)
        {
            cout << "catch(catch bad_alloc&)" << endl;
        }
    }
    
    int main()
    {
        ex_func_1();
    
        return 0;
    }
      :[g++]
    func = 0
    
      :[vc++2010]
    func = 00000000
    
      :[bcc]
    func = 0x00401474
    catch(catch bad_alloc&)
    
      :
         ,g++,vc++2010          new_handler()   ;
               gcc        new_handler()   ,     bad_alloc   。             

    実験2:異なるコンパイラnew失敗挙動
    void ex_func_2()
    {
        Test* pt = new Test();
        
         cout << "pt = " << pt << endl;
         
         delete pt;
         
         pt = new Test[5];
         
         cout << "pt = " << pt << endl;
         
         delete[] pt;
    }
    
    int main()
    {
        ex_func_2();
    
        return 0;
    }
      :[g++]
    Test()
       
    
      :[vc++2010]
    operator new: 4
    pt = 00000000
    operator new[]: 24
    pt = 00000000
    
      :[bcc]
    operator new: 4
    pt = 00000000
    operator new[]: 24
    pt = 00000000
    
      :
    g++                   : 
    new        NULL,      0        ,      。     ,m_value = 0,     。
    
    vc++2010:
       new       NULL,     ,         
    
    bcc:
       new       NULL,     ,         

    質問:コンパイラにまたがってnewの動作を統一し、コードの移植性を高めるにはどうすればいいのでしょうか.
  • ソリューション【動的メモリ割り当てに失敗した場合、空のポインタを返す】
  • グローバルレンジ(推奨しない)
  • new/deleteの実装を再定義し、異常
  • を投げ出さない
  • カスタムnew_handler()関数、異常
  • を投げ出さない
  • クラス階層範囲
  • new/deleteを再ロードし、異常
  • を投げ出さない
  • このダイナミックメモリ割り当て
  • nothrowパラメータを使用して、newが異常
  • を放出しないことを示す.


    プログラミング実験:ダイナミックメモリ申請
    実験1:クラス階層範囲
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    class Test
    {
    private:
        int m_value;
        
    public:
        Test()
        {
            cout << "Test()" << endl;
            
            m_value = 0;
        }
        
        ~Test()
        {
            cout << "~Test()" << endl;
        }
        
        void* operator new (unsigned int size) throw()     //     !
        {
            cout << "operator new: " << size << endl;
            
            // return malloc(size);
            
            return NULL;                                  //     !         
        }
        
        void operator delete(void* p) 
        {
            cout << "operator delete: " << p << endl;
            
            free(p);
        }
        
        void* operator new[] (unsigned int size) throw()  //     ! 
        {
            cout << "operator new[]: " << size << endl;
            
            // return malloc(size);
            
            return NULL;                                 //     !         
        }
        
        void operator delete[](void* p)
        {
            cout << "operator delete[]: " << p << endl;
            
            free(p);
        }
    };
    
    void ex_func_2()
    {
        Test* pt = new Test();
        
         cout << "pt = " << pt << endl;
         
         delete pt;
         
         pt = new Test[5];
         
         cout << "pt = " << pt << endl;
         
         delete[] pt;
    }
    
    int main()
    {
        ex_func_2();
    
        return 0;
    }
      :[g++]
    operator new: 4
    pt = 0
    operator new[]: 24
    pt = 0
    
      :[vc++2010]
    operator new: 4
    pt = 00000000
    operator new[]: 24
    pt = 00000000
    
      :[bcc]
    operator new: 4
    pt = 00000000
    operator new[]: 24
    pt = 00000000
    

    実験2:単一ダイナミックメモリ割り当て範囲
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    void ex_func_3()
    {
         int* p = new(nothrow) int[10];    //     !
        
         cout << "p = " << p << endl;
         
         delete p;
    }
    
    int main()
    {
        ex_func_3();
    
        return 0;
    }
      :
    p = 0x8300008
    
  • 実験結論
  • すべてのコンパイラがC++の標準仕様
  • に従うわけではありません.
  • コンパイラはnewのインプリメンテーションを再定義し、インプリメンテーションからbad_を放出することができる.alloc異常
  • コンパイラのデフォルト実装では、グローバルなnew_が設定されていない可能性があります.handler()関数
  • 移植性の要求が高いコードについてはnewの具体的な詳細
  • を考慮する必要がある.

    小結
  • 異なるコンパイラの動的メモリ割り当てにおける実装の詳細は
  • 異なる.
  • malloc関数は、メモリ申請に失敗したときにNULL値
  • を返す.
  • newキーワードメモリ申請に失敗した場合
  • は、NULL値
  • を返すことができる
  • bad_を投げ出す可能性がありますalloc異常

  • newに関する小さな知識点補足:指定したメモリ領域にオブジェクトを作成する(構造関数を手動で呼び出す必要がある)
    #include 
    
    using namespace std;
    
    int main()
    {
        int bb[2] = {0};
    
        struct ST
        {
            int x;
            int y;
        };
    
        ST* pt = new(bb) ST();    //     !
    
        pt->x = 1;
        pt->y = 2;
        
        cout << bb[0] << endl;
        cout << bb[1] << endl;
    
        pt->~ST();                //         
    
        return 0;
    }
      :
    1
    2
    

    以上の内容はディテソフトウェア学院シリーズの課程を参考にして、オリジナルを保護してください!