558

C ++では、データを割り当てて解放する方法が複数あることがわかります。電話をかけるときmallocは電話をかけ、演算子freeを使用するときnewはペアリングする必要がdeleteあり、2つを組み合わせるのは間違いです(たとえば、free()作成されたものを呼び出す)new演算子を使用)が、実際のプログラムで/をいつ使用する必要があるのか​​、および/をいつ使用する必要があるのか​​が明確ではありませmallocfreenewdelete

C ++の専門家の方は、この点に関して従う経験則や規則を教えてください。

4

20 に答える 20

455

Cを使用するように強制されない限り、を使用しないでください malloc。常に使用してnewください。

大量のデータが必要な場合は、次のようにします。

char *pBuffer = new char[1024];

これは正しくありませんが、注意してください。

//This is incorrect - may delete only one element, may corrupt the heap, or worse...
delete pBuffer;

代わりに、データの配列を削除するときにこれを行う必要があります。

//This deletes all items in the array
delete[] pBuffer;

キーワードはそれを行うC++の方法であり、型に。というコンストラクターnewが確実に含まれるようにします。キーワードはタイプセーフでもあります、タイプセーフではありません。newmalloc

それを使用するのが有益だと私が考える唯一の方法は、データのバッファのサイズmallocを変更する必要がある場合です。キーワードには、のような類似の方法はありません。この関数は、メモリのチャンクのサイズをより効率的に拡張できる場合があります。newreallocrealloc

new/freemalloc/を混在させることはできませんdelete

注:この質問の一部の回答は無効です。

int* p_scalar = new int(5);  // Does not create 5 elements, but initializes to 5
int* p_array  = new int[5];  // Creates 5 elements
于 2008-10-08T19:48:43.073 に答える
161

簡単に言えmallocば、正当な理由がない限り C++ には使用しないでください。mallocには、C++ で使用すると多くの欠陥があり、new克服するように定義されています。

C++ コードの new によって修正された欠陥

  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 (plain old data)である場合、最初の例のように、半賢明に使用mallocしてメモリを割り当てることができます。f2

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

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

    明らかな診断なしで、mallocのも悪くなります。f2ここでの例は些細なことですが、(たとえば、非 POD メンバーを追加することによって、基本クラスで) 非 POD 性をさらに遠くに誤って導入する可能性があります。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)));
    }
    

    ただし、Boost は、 C++11 またはその他のコンパイラ拡張機能がないと、型が POD であるかどうかを判断できません。

  3. mallocNULL割り当てが失敗した場合に戻ります。new投げstd::bad_allocます。後でNULLポインターを使用した場合の動作は未定義です。例外は、スローされたときに明確なセマンティクスを持ち、エラーのソースからスローされます。malloc呼び出しごとに適切なテストでラップするのは面倒で、エラーが発生しやすいようです。(すべての良い作業を元に戻すのを忘れる必要があるのは 1 回だけです)。例外は、呼び出し元が適切に処理できるレベルまで伝播することができますが、NULL有意義に戻すのははるかに困難です。関数を拡張してsafe_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することもできます。

于 2011-11-01T17:04:54.523 に答える
57

C ++ FQA Liteから:

[16.4]信頼できる古いmalloc()の代わりに新しいものを使用する必要があるのはなぜですか?

FAQ:コンストラクタ/デストラクタの新規/削除呼び出し。newはタイプセーフですが、mallocはそうではありません。newはクラスによってオーバーライドできます。

FQA:FAQで言及されているnewの長所は長所ではありません。コンストラクタ、デストラクタ、および演算子のオーバーロードはガベージであり(ガベージコレクションがない場合はどうなるかを参照してください)、ここでは型安全性の問題は非常に小さいです(通常はmallocによって返されたvoid*を正しいポインター型にキャストして、型付きポインター変数に割り当てます。これは煩わしいかもしれませんが、「安全ではない」とは言えません。

ああ、そして信頼できる古いmallocを使用すると、同じように信頼できる古いreallocを使用できるようになります。残念ながら、新しいオペレーターの更新などはありません。

それでも、言語がC ++の場合でも、newは、言語全体で使用される一般的なスタイルからの逸脱を正当化するのに十分なほど悪くはありません。特に、重要なコンストラクターを持つクラスは、単にオブジェクトをmallocすると、致命的な方法で誤動作します。では、コード全体でnewを使用してみませんか?人々が新しい演算子をオーバーロードすることはめったにないので、おそらくあまり邪魔にならないでしょう。そして、彼らが新しく過負荷になった場合、あなたはいつでも彼らにやめるように頼むことができます。

すみません、抵抗できませんでした。:)

于 2008-10-08T20:24:37.527 に答える
51

C++ では常に new を使用します。型指定されていないメモリのブロックが必要な場合は、演算子 new を直接使用できます。

void *p = operator new(size);
   ...
operator delete(p);
于 2008-10-08T19:54:11.533 に答える
45

new vs malloc()

1) new is an operator, while malloc() is a function.

2) new calls constructors, while malloc() does not.

3) new returns exact data type, while malloc() returns void *.

4) new never returns a NULL (will throw on failure) while malloc() returns NULL

5) Reallocation of memory not handled by new while malloc() can

于 2015-11-26T10:06:05.297 に答える
33

c中心のライブラリとAPIによって管理されるメモリを割り当てるためmallocのみ使用します。制御するすべてのものにand (およびバリアント)を使用します。free newdelete[]

于 2008-10-08T19:51:13.320 に答える
15

との間には大きな違いが1つmallocありnewます。mallocメモリを割り当てます。Cではメモリの塊がオブジェクトであるため、これはCにとっては問題ありません。

C ++では、POD型(C型に似ています)を扱っていない場合は、実際にオブジェクトをそこに置くために、メモリ位置でコンストラクターを呼び出す必要があります。多くのC++機能がオブジェクトを自動的に非PODにするため、非PODタイプはC++では非常に一般的です。

newメモリを割り当て、そのメモリ位置にオブジェクトを作成します。非PODタイプの場合、これはコンストラクターを呼び出すことを意味します。

あなたがこのようなことをするなら:

non_pod_type* p = (non_pod_type*) malloc(sizeof *p);

取得したポインタはオブジェクトを指していないため、逆参照できません。使用する前にコンストラクターを呼び出す必要があります(これはplacementを使用して行われますnew)。

一方、次の場合:

non_pod_type* p = new non_pod_type();

newオブジェクトが作成されたため、常に有効なポインタを取得します。

PODタイプの場合でも、2つの間に大きな違いがあります。

pod_type* p = (pod_type*) malloc(sizeof *p);
std::cout << p->foo;

によって作成されたPODオブジェクトは初期化されていないため、このコードは不特定の値を出力しmallocます。

を使用newすると、呼び出すコンストラクターを指定して、明確に定義された値を取得できます。

pod_type* p = new pod_type();
std::cout << p->foo; // prints 0

本当に必要な場合は、useを使用newして初期化されていないPODオブジェクトを取得できます。詳細については、この他の回答を参照してください。

もう1つの違いは、障害時の動作です。メモリの割り当てに失敗すると、例外をスローしmallocながらnullポインタを返します。new

前者は、使用する前に返されたすべてのポインターをテストする必要がありますが、後者は常に有効なポインターを生成します。

これらの理由から、C ++コードではnew、ではなく、を使用する必要がありますmalloc。ただし、それでも、new後でリリースする必要のあるリソースを取得するため、「オープン」で使用しないでください。使用するときnewは、その結果をすぐにリソース管理クラスに渡す必要があります。

std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak
于 2011-11-01T18:25:37.973 に答える
6

できないnewことがいくつかあります。malloc

  1. newそのオブジェクトのコンストラクターを呼び出してオブジェクトを構築します
  2. new割り当てられたメモリの型キャストを必要としません。
  3. 大量のメモリを割り当てる必要はなく、多数のオブジェクトを構築する必要があります。

したがって、 を使用する場合はmalloc、上記のことを明示的に行う必要がありますが、これは必ずしも実用的ではありません。さらに、newオーバーロードすることはできますが、オーバーロードするmallocことはできません。

于 2014-01-15T14:45:51.287 に答える
5

構築/破棄を必要とせず、再割り当てが必要なデータ (たとえば、int の大規模な配列) を扱う場合は、new-memcpy よりもはるかに高速な再割り当てを提供する malloc/free が適切な選択であると考えています。 -delete (私の Linux ボックスにはありますが、これはプラットフォームに依存する可能性があると思います)。POD ではなく、構築/破棄が必要な C++ オブジェクトを操作する場合は、new および delete 演算子を使用する必要があります。

とにかく、速度の向上を利用できるのであれば(mallocされたメモリを解放し、newで割り当てられたオブジェクトを削除するという条件で)両方を使用すべきではない理由がわかりません(大規模な配列を再割り当てしている場合、時には重要なものです) POD の) realloc があなたに与えることができます。

ただし、必要でない限り、C++ の new/delete に固執する必要があります。

于 2013-04-09T12:23:20.363 に答える
2

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

于 2008-10-08T19:52:10.087 に答える
1

次のシナリオでは、コンストラクターを呼び出すため、newを使用できません。

class  B  {
private:
    B *ptr;
    int x;
public:
    B(int n)  {
        cout<<"B: ctr"<<endl;
        //ptr = new B;  //keep calling ctr, result is segmentation fault
        ptr = (B *)malloc(sizeof(B));
        x = n;
        ptr->x = n + 10;
    }
    ~B()  {
        //delete ptr;
        free(ptr);
        cout<<"B: dtr"<<endl;
    }
};
于 2012-08-17T00:54:23.110 に答える
1

低い観点から見ると、new はメモリを与える前にすべてのメモリを初期化しますが、malloc はメモリの元の内容を保持します。

于 2011-08-14T20:31:35.713 に答える
0

newanddelete演算子はクラスと構造体を操作できますが、andmallocfreeキャストする必要があるメモリ ブロックでのみ機能します。

を使用new/deleteすると、割り当てられたメモリを必要なデータ構造にキャストする必要がないため、コードを改善するのに役立ちます。

于 2008-10-08T20:42:26.447 に答える
0

ところで、malloc を使用するコードがある場合は、次の正規表現を使用します。

検索する:

\((\w+)\*\)malloc\((\w+)\)

と置換する:

new \1[\2]
于 2022-01-06T22:00:22.693 に答える
-4

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

于 2012-07-26T05:41:38.067 に答える