c++ array - 我在哪些情況下使用malloc vs new?




del (16)

除非你被迫使用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;

new關鍵字是C ++的方法,它會確保你的類型的構造函數被調用new關鍵字也更安全,malloc根本不是類型安全的。

如果您需要更改數據緩衝區的大小,唯一可以考慮的方法是使用malloc有利。 new關鍵字沒有類似reallocrealloc函數可能能夠更有效地擴展一塊內存的大小。

值得一提的是,你不能混用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

我在C ++中看到有多種分配和釋放數據的方法,我知道當你調用malloc時應該free調用,當你使用new操作符時,你應該配對delete ,混合兩者是錯誤的(例如,Calling free()new操作符創建的東西),但我不清楚什麼時候應該使用malloc / free ,何時應該在我的真實世界程序中使用new / delete

如果您是C ++專家,請告訴我您在這方面遵循的任何規則或慣例。


new將初始化該結構的默認值,並將其中的引用正確鏈接到它自身。

例如

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

所以new struct test_s將返回一個帶有工作引用的初始化結構,而malloc'ed版本沒有默認值,並且實例引用不會被初始化。


mallocnew之間有一個很大的區別。 malloc分配內存。 這對C來說很好,因為在C中,一塊內存是一個對象。

在C ++中,如果你沒有處理POD類型(類似於C類型),你必須在內存位置調用一個構造函數來實際擁有一個對象。 非POD類型在C ++中非常常見,因為許多C ++特性使對象自動成為非POD。

new分配內存在該內存位置創建一個對象。 對於非POD類型,這意味著調用構造函數。

如果你做這樣的事情:

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

您獲得的指針不能被解除引用,因為它不指向對象。 在使用它之前,您需要先調用一個構造函數(並且這是使用new位置完成的)。

另一方面,如果你這樣做:

non_pod_type* p = new non_pod_type();

你會得到一個始終有效的指針,因為new了一個對象。

即使是POD類型,兩者之間也存在顯著差異:

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

這段代碼會打印一個未指定的值,因為由malloc創建的POD對像不會被初始化。

new ,你可以指定一個構造函數來調用,從而得到一個定義好的值。

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

如果你真的想要它,你可以使用new來獲得未初始化的POD對象。 有關更多信息,請參閱其他答案

另一個區別是失敗後的行為。 當它分配內存失敗時, malloc返回一個空指針,而new拋出一個異常。

前者要求你在使用之前測試每個返回的指針,而後者將始終產生有效的指針。

由於這些原因,在C ++代碼中,你應該使用new而不是malloc 。 但即使如此,你也不應該使用new “開放式”,因為它獲得了你稍後需要發布的資源。 當你使用new你應該立即將它的結果傳遞給一個資源管理類:

std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak

如果您使用的數據不需要構建/銷毀並需要重新分配(例如,大量整數),那麼我相信malloc / free是一個不錯的選擇,因為它可以讓您重新分配,這比new-memcpy -delete(它在我的Linux機器上,但我想這可能取決於平台)。 如果您使用不是POD的C ++對象並需要構建/銷毀,那麼您必須使用新的和刪除操作符。

無論如何,我不明白為什麼你不應該同時使用它們(假設你釋放你的malloced內存並刪除分配了新對象的對象),如果可以利用速度提升(有時很重要,如果你重新分配大型數組的POD)realloc可以給你。

除非你需要它,否則你應該堅持使用C ++中的新/刪除。


要回答你的問題,你應該知道mallocnew之間的區別 。 區別很簡單:

malloc 分配內存 ,而new 分配內存,並調用你分配內存的對象的構造函數

所以,除非你被限制在C中,否則你不應該使用malloc,特別是在處理C ++對象時。 這將是打破你的計劃的秘訣。

freedelete的區別也是相同的。 區別在於除了釋放內存之外, delete還會調用對象的析構函數。


總是在C ++中使用新的。 如果你需要一塊無類型的內存,你可以直接使用operator new:

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

C ++ FQA Lite開始

[16.4]為什麼我應該使用new而不是可靠的舊malloc()?

FAQ:new / delete調用構造函數/析構函數; 新是類型安全的,malloc不是; 新的可以被一個類覆蓋。

FQA:FAQ提到的新特性不是美德,因為構造函數,析構函數和運算符重載都是垃圾(看看沒有垃圾回收會發生什麼?),類型安全問題在這裡非常小(通常你有將malloc返回的void *轉換為正確的指針類型,將其分配給一個類型化的指針變量,這可能很煩人,但遠非“不安全”)。

哦,並且使用可靠的舊malloc可以使用同樣值得信賴和舊的realloc。 太糟糕了,我們沒有一個閃亮的新運營商更新或什麼。

儘管如此,即使語言是C ++,new也不足以證明與一種語言使用的通用風格的偏差。 特別是,如果你只是簡單地使用malloc對象,那麼帶有不平凡構造函數的類將會以致命的方式行事不端。 那麼為什麼不在整個代碼中使用新的? 人們很少重載運營商新的,所以它可能不會太多。 如果他們超載新的,你總是可以讓他們停下來。

對不起,我無法抗拒。 :)


如果您想要將C代碼移植到C ++,則可以在其中留下任何malloc()調用。 對於任何新的C ++代碼,我建議使用new代替。


從較低的角度來看,new將在給出內存之前初始化所有內存,而malloc將保留內存的原始內容。


簡短的答案是:不要使用malloc for C ++,但沒有充分的理由這麼做。 malloc在與C ++一起使用時有許多缺陷,這些缺陷被定義為要克服。

新的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(普通的舊數據),那麼你可以半理性地使用malloc來為它分配內存,就像第一個例子中的f2那樣。

    如果某種類型是POD,它並不是那麼明顯。 事實上,給定類型可能會從POD更改為非POD,而不會導致編譯器錯誤,並且可能很難調試問題,這是一個重要因素。 例如,如果有人(可能是另一位程序員,在維護期間,很多時候會做出更改,導致foo不再是POD,那麼編譯時就不會出現明顯的錯誤,例如:

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

    會使f2malloc也變得不好,沒有任何明顯的診斷。 這裡的示例很簡單,但可能會意外地將非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. 如果分配失敗, malloc返回NULLnew會拋出std::bad_alloc 。 稍後使用NULL指針的行為是未定義的。 拋出異常時具有乾淨的語義,並且從錯誤源拋出異常。 在每次調用時用適當的測試對malloc進行包裝看起來很乏味且容易出錯。 (你只需要忘記一次就可以撤消所有的好工作)。 可以允許異常傳播到調用者能夠合理地處理它的級別,其中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和placement new那麼你可以使用new來開始!


在下面的場景中,我們不能使用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;
    }
};

malloc()用於在C中動態分配內存,而c ++中的new()完成相同的工作。 所以你不能混用兩種語言的編碼約定。 如果你詢問calloc和malloc()之間的區別,那將會很好。


使用malloc用於分配將由c-centric庫和API管理的內存。 使用newdelete (和[]變種)為你控制的一切。


新vs malloc()

1) new是一個運算符 ,而malloc()是一個函數

2) new調用構造函數 ,而malloc()不調用。

3) new返回確切的數據類型 ,而malloc()返回void *

4) new從不返回NULL (將拋出失敗),而malloc()返回NULL

5) malloc()可以重新分配未由new處理的內存


如果您使用的是c ++,那麼嘗試使用new / delete而不是malloc / calloc,因為它們是operator自身,與它們的malloc / calloc相比,您曾經為它們包含另一個頭。因此,不要在單個編碼中混合使用兩種不同的語言他們的工作在每種方式都是相似的,都從哈希表中的堆段動態地分配內存。


這已經討論過( 什麼是顯式構造函數 )。 但我必須說,它缺乏這裡的詳細描述。

此外,如上所述,使用一個參數構造函數(包括那些具有arg2,arg3,...的默認值的構造函數)總是一個很好的編碼實踐。 像C ++一樣:如果你不這樣做 - 你會希望你做到......

類的另一個好習慣是使復制構造和賦值私有(也就是禁用它),除非你真的需要實現它。 這避免了在使用C ++默認為您創建的方法時最終有指針副本。 另一種方法是從boost :: noncopyable派生。





c++ memory-management malloc new-operator