[c++] どのような場合にmalloc vs newを使用しますか?



Answers

簡単な答えは、そうすることに本当に正当な理由がないのにC ++にmallocを使わないでください。 mallocは、C ++で使用されたときにいくつかの欠点があります。これは、 newが克服するために定義されたものです。

C ++コードの不具合修正

  1. mallocはタイプセーフではありません。 C ++では、 void*からの戻り値をキャストする必要があります。 これにより、潜在的に多くの問題が発生します。

    #include <stdlib.h>
    
    struct foo {
      double d[5];
    }; 
    
    int main() {
      foo *f1 = malloc(1); // error, no cast
      foo *f2 = static_cast<foo*>(malloc(sizeof(foo)));
      foo *f3 = static_cast<foo*>(malloc(1)); // No error, bad
    }
    
  2. それはそれよりも悪いです。 問題の型がPOD(普通の古いデータ)の場合、最初の例でf2が行うように、 mallocを半賢明に使ってメモリを割り当てることができます。

    タイプがPODの場合はそれほど明白ではありません。 特定のタイプがPODから非PODに変わる可能性があり、コンパイルエラーが発生せず、問題をデバッグする可能性が非常に高いことが重要な要素です。 たとえば、誰か(メンテナンス中に別のプログラマが後になってfooがPODにならないように変更した場合、コンパイル時に明白なエラーは表示されません。

    struct foo {
      double d[5];
      virtual ~foo() { }
    };
    

    f2mallocも明らかな診断なしで悪くなるでしょう。 ここの例は簡単ですが、POD以外のメンバーを追加するなど、非PODnessをはるかに遠くに導入することも可能です(たとえば、ベースクラスでは)。 C ++ 11 / boostをお持ちの場合、 is_podを使用してこの仮定が正しいことを確認し、そうでない場合はエラーを生成することができます:

    #include <type_traits>
    #include <stdlib.h>
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      return static_cast<foo*>(malloc(sizeof(foo)));
    }
    

    ブーストでは、型が C ++ 11やその他のコンパイラ拡張機能なしでPODであるかどうかを判断することはできません

  3. 割り当てが失敗した場合、 mallocNULL返しNULLnewstd::bad_allocをスローしstd::bad_alloc 。 後でNULLポインタを使用する動作は未定義です。 例外がスローされ、エラーの発生源からスローされると、例外はクリーンなセマンティクスを持ちます。 適切なテストでmallocをすべての呼び出しで折り返すことは退屈でエラーが起こりやすいようです。 (あなたはその良い仕事すべてを元に戻すために一度忘れなければならない)。 呼び出し側がそれを感知できるように処理できるレベルに例外を伝播させることができNULLは意味をなさないように戻すのがずっと難しくなりNULLsafe_foo_malloc関数を拡張して例外をスローしたり、プログラムを終了したり、ハンドラを呼び出すことができます:

    #include <type_traits>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      foo *mem = static_cast<foo*>(malloc(sizeof(foo)));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return mem;
    }
    
  4. 基本的に、 mallocはCの機能であり、 new C ++の機能です。 その結果、 mallocはコンストラクタでうまく動作せず、バイトのチャンクだけを調べます。 safe_foo_mallocさらに拡張して、 newプレースメントを使用することもできます:

    #include <stdlib.h>
    #include <new>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      void *mem = malloc(sizeof(foo));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return new (mem)foo();
    }
    
  5. 私たちのsafe_foo_malloc関数はそれほど汎用的ではありません。理想的には、 fooだけでなく、どんな型でも処理できるものが必要です。 デフォルト以外のコンストラクタのテンプレートと可変テンプレートでこれを実現できます:

    #include <functional>
    #include <new>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    template <typename T>
    struct alloc {
      template <typename ...Args>
      static T *safe_malloc(Args&&... args) {
        void *mem = malloc(sizeof(T));
        if (!mem) {
           my_malloc_failed_handler();
           // or throw ...
        }
        return new (mem)T(std::forward(args)...);
      }
    };
    

    これまでに確認したすべての問題を修正するにあたり、デフォルトのnew演算子を実際に再発明しました。 mallocとプレースメントをnewに使うつもりならば、 newで始めることもできます!

Question

私はC ++で複数の方法でデータを割り当て、解放することができますmallocを呼び出すときはfreeで呼び出すべきですが、 new演算子を使用するときはdeleteとペアを組むべきであることを理解しています。 free()new演算子で作成されたものfree()を使用していますが、 malloc / freeをいつ使うべきか、現実世界のプログラムでnew / deleteを使うべきかについてはわかりません。

あなたがC ++の専門家であれば、この点に関してあなたが従う規則や規則を教えてください。




新しい/削除の代わりにmalloc / freeを使用することを検討するまれなケースは、reallocを使用してreallocを使用してC ++で再割り当てする(単純なポッドタイプでオブジェクトではなく)割り当ておよび再割り当てする場合です(これはもっとC ++アプローチ)




あなたの質問に答えるには、 mallocnew違いを知っおく必要があります。 違いは簡単です:

malloc はメモリを割り当てnewはメモリを割り当て、メモリを割り当てるオブジェクトのコンストラクタ呼び出します。

だから、あなたがCに制限されていない限り、特にC ++オブジェクトを扱うときは、mallocを使用しないでください。 それはあなたのプログラムを壊すためのレシピになります。

また、 freedelete違いはまったく同じです。 違いは、 deleteはメモリを解放するだけでなくオブジェクトのデストラクタを呼び出すことです。




構築/破壊を必要とせず、再割り当てが必要なデータ(intの大きな配列など)を扱う場合、malloc / freeは新しいmemcpyより速いreallocを提供するので、良い選択であると私は信じています-delete(これは私のLinuxマシン上にありますが、これはプラットフォームに依存するかもしれません)。 PODではなく、構築/破棄が必要なC ++オブジェクトを扱う場合は、new演算子とdelete演算子を使用する必要があります。

とにかく、私はなぜ高速メモリ(大容量の配列を再割り当てしている場合は重要なものですPODの)reallocがあなたに与えることができます。

あなたがそれを必要としない限り、C ++で新規/削除に固執するべきです。




常にC ++で新しいものを使用してください。 タイプのないメモリブロックが必要な場合は、operator newを直接使用することができます。

void *p = operator new(size);
   ...
operator delete(p);



C ++に移植したいCコードがあれば、その中にmalloc()呼び出しを残すことができます。 新しいC ++コードでは、代わりにnewを使うことをお勧めします。




新しいvs malloc()

1) new演算子であり、 malloc()関数です。

2) malloc()new呼び出しコンストラクタを呼び出しません。

3) new正確なデータ型を返しますが、 malloc()void *を返します

4) newは、 malloc()がNULLを返す間にNULLを返すことはありません(失敗時に投げます)

5) malloc()newメモリで処理できないメモリの再割り当て




malloc()はC言語でメモリを動的に割り当てるために使用され、同じ作業はc ++でnew()によって行われます。 したがって、2つの言語のコーディング規則を混在させることはできません。 あなたがcallocとmalloc()の違いを尋ねたなら、




newは構造体のデフォルト値を初期化し、そこにある参照を正しくリンクします。

例えば

struct test_s {
    int some_strange_name = 1;
    int &easy = some_strange_name;
}

したがって、 new struct test_sは作業参照で初期化された構造体を返しますが、mallocされたバージョンはデフォルト値を持たず、内部参照は初期化されません。




Related