博客 / 詳情

返回

c++ 對象在棧上還是在堆上?

c++的對象到底在棧上還是分配在堆上?

首先,毋庸置疑,使用new和malloc系列函數分配的對象,一定是在堆上的。

Object *obj = new Object();

有爭議的是

Object obj;

它是在棧上還是在堆上呢?

要回答這個問題,首先我們需要理解這句話的意思,這句話並不代表在棧上分配內存,它代表的是讓obj具有“自動存儲(automatic storage)”的性質。所謂的“自動存儲”,意思是這個對象的存儲位置取決於其聲明所在的上下文。如果這個語句出現在函數內部,那麼它就在棧上創建對象,此時obj變量和obj指代的對象(此時obj本質上其實是obj指代對象的首地址)都在棧上。
如果這個語句不是在函數內部,而是作為一個類的成員變量,則取決於這個類的對象是如何分配的。考慮下面的代碼:

class Test{
    Object obj;
}

Test *test = new Test;

test指針是在棧上,它所指代的對象Test是存在堆上,那麼obj變量和obj對象就在堆上。

class Test{
    Object obj;
}

Test test;

test變量在棧上,test對象在棧上,那麼obj變量和obj對象就在棧上。

遵循這麼一個原則:
指針變量和普通變量由上下文定義,指針所指向的內存在堆上,普通變量所指代的對象由上下文定義。

棧大小

棧大小是有默認值的,如果申請的臨時變量太大就會超過棧大小,造成棧溢出。

它的默認值是可以修改的,一般,在unix-like平台,棧的大小是由環境變量控制的,所以不能通過設置編譯器(像gcc)的任何編譯標誌來設置;在windows平台,棧的大小是包含在可執行文件裏的,它可以在visual c++的編譯過程中設置,但在gcc裏是不可行的。

方法為:
項目->屬性->鏈接器->系統->堆棧保留大小 (字節數)

在一般情況下,不同平台默認棧大小如下所示(僅供參考)

SunOS/Solaris 8172K bytes (Shared Version)
Linux 10240K bytes
Windows 1024K bytes (Release Version)
AIX 65536K bytes

演示

棧空間

代碼

#include <iostream>

class Test {
public:
    Test() { std::cout << "Test" << std::endl; }
    ~Test() { std::cout << "~Test" << std::endl; }

private:
    char a[1024 * 1024];
};

class TestContainer {
public:
    TestContainer() { std::cout << "TestContainer" << std::endl; }
    ~TestContainer() { std::cout << "~TestContainer" << std::endl; }

private:
    Test test;
};

int main(int argc, char* argv[]) {
    TestContainer t;
    while (1) {}
    return 0;
}
  1. 棧大小1MB(默認值),申請棧空間1MB
    結果:程序崩潰,stack overflow

image.png

  1. 棧大小1048577(1024*1024+1,即1MB多1B),申請棧空間1MB
    結果:程序正常

image.png

堆空間

#include <iostream>

class Test {
public:
    Test() { std::cout << "Test" << std::endl; }
    ~Test() { std::cout << "~Test" << std::endl; }

private:
    char a[1024 * 1024];
};

class TestContainer {
public:
    TestContainer() { std::cout << "TestContainer" << std::endl; }
    ~TestContainer() { std::cout << "~TestContainer" << std::endl; }

private:
    Test test;
};

int main(int argc, char* argv[]) {
    TestContainer* t = new TestContainer;
    while (1) {}
    return 0;
}
  1. 棧大小1MB,申請堆1MB
    結果:程序正常
  2. 棧大小1MB,申請堆10MB
    結果:程序正常
user avatar laughingzhu 頭像 huishou 頭像 chongdianqishi 頭像 suporka 頭像 musicfe 頭像 user_ze46ouik 頭像 fyuanlove 頭像 lihaixing 頭像 gozhuyinglong 頭像 ipromise 頭像 carloslab 頭像 yookoo 頭像
15 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.