[c++]從新瞭解delete[]

引言

你們都知道new了一個變量,須要使用delete釋放內存,而new出了一個數組,須要使用對應的delete[]釋放內存。但我好像在哪看見過一種說法:針對系統內置類型,使用new分配後的無論是數組仍是非數組形式內存空間用deletedelete[]均可以。光說沒用,寫代碼測試一下(測試環境 centos, g++4.8.5)。html

內置普通變量:ios

// test.cpp
#include <iostream>
#include <thread>
using namespace std;

#define N (1024*1024) // 1M
int main()
{
    while(1) {
        char *a = new char[N]; // 4M
        //delete[] a;
        std::this_thread::sleep_for(std::chrono::milliseconds(5)); //5ms延時
        printf("running\n");
    }
}
// 編譯 g++ test.cpp -o test -std=c++11
// 1. 不delete時,內存一直在漲
// 2. 使用delete 時, 內存不漲
// 3. 使用delete[] 時, 內存不漲

測試發現,說的確實有道理啊,內置類型的數組不必使用delete[]c++

因而再測測自定義類型:centos

#include <iostream>
#include <thread>
using namespace std;

#define N (1024*1024) // 1M
class A{
public:
    char a;
    A() : a('a') { }
};
int main()
{
    while(1) {
        A *a = new A[N]; // 4M
        //delete[] a;
        std::this_thread::sleep_for(std::chrono::milliseconds(5)); //5ms延時
        printf("running\n");
    }
}
// 1. 不delete時,內存一直在漲
// 2. 使用delete 時, 內存不漲
// 3. 使用delete[] 時, 內存不漲

what?結果和內置類型同樣???這是爲何,因而趕忙去查一查資料,發現本身對newdelete的理解確實錯了!趕忙從新總結一波。數組

delete和delete[]的區別

記住一句話:new先分配內存,再調用構造函數delete先調用析構函數,再釋放內存。函數

那麼,若是new了一個數組,調用幾回構造函數呢,調用的是那一個構造函數呢;delete數組和delete[]數組又分別調用幾回析構呢。能夠作個實驗:測試

#include <iostream>
#include <thread>
using namespace std;

class String {
public:
    // 若是刪除無參的構造函數
    // new String[]的時候會報錯
    String() {
        cout << "String()" << endl;
        m_data = new char;
    }
    String(int n) {
        cout << "String(int n)" << endl;
        m_data = new char[n];
    }
    ~String() {
        cout << "~String()" << endl;
        delete[] m_data;
    }

private:
    char* m_data;
};

int main()
{
    String* s = new String[3]; // 三次無參構造函數
//    delete s; // 一次析構函數
    delete[] s;  // 三次析構函數
}

// 1. new String[3],調用了3次無參的構造函數!
// 因此若是沒有無參構造函數會報錯
// error: no matching function for call to 'String::String()'
// 2. 使用delete 時,調用了一次構造函數
// 3. 使用delete[] 時, 調用了三次析構函數

其實看完這個例子,就能明白爲何要用delete[]而不是delete了,由於只掉用一次析構函數,對於上面的代碼是錯的,會發生內存泄漏。由於String類中有指針成員。這些指針成員必須跟隨着String對象的銷燬而銷燬。this

下面是內存分佈圖:spa

內存分佈圖.png

在使用delete的時候,其實是會刪除三個String對象佔據的內存,可是隻有在調用String類的析構函數的時候,纔會銷燬對象內部的m_data變量所指向的字符串。而delete只會調用第一個對象的析構函數,後面兩個String對象的析構函數不夠調用。而delete[]能夠保證這一點。在使用new的時候,會記錄數組的長度,以下圖,指針

new出來的變量的內存圖.png

delete[]會根據記錄的長度決定析構次數。

因此說,其實若是類中沒有new出來的資源,都是棧上的資源,無需調用構造函數來釋放資源的話,其實調用deletedelete[]沒有區別。而若是類中有指針變量,則對於這種對象的數組,必須使用delete[]

能夠編寫代碼測試,當一個類中只有棧上的變量的時候,它組成的數組用delete刪除是不會發生內存泄漏的。引言中的測試也證實了這一點。

總結

緊緊記住:new先分配內存,再調用構造函數delete先調用析構函數,再釋放內存。delete只會調用數組第一個對象的析構函數,而delete[]會調用數組中全部對象的析構函數。雖然有時候沒有影響,可是最好仍是遵循規範,防止錯誤的發生,對於數組都使用delete[]

個人簡書博客

參考

[delete 和 delete []的真正區別](https://www.cnblogs.com/wangj...

相關文章
相關標籤/搜索