2011-01-14 70 views
7

Tôi đang bối rối về việc cấp phát bộ nhớ trong C++ về mặt bộ nhớ như vùng dữ liệu Const, Stack, Heap, Freestore, Heap và Global/Static area. Tôi muốn hiểu mẫu phân bổ bộ nhớ trong đoạn mã sau. Bất cứ ai có thể giúp tôi hiểu điều này. Nếu có bất kỳ điều gì khác ngoài các loại biến được đề cập trong ví dụ để giúp hiểu khái niệm tốt hơn, vui lòng thay đổi ví dụ.Phân bổ bộ nhớ trong C++

class FooBar 
{ 
     int n; //Stored in stack? 

     public: 

      int pubVar; //stored in stack? 

      void foo(int param) //param stored in stack 
      { 
       int *pp = new int; //int is allocated on heap. 
       n = param; 
       static int nStat; //Stored in static area of memory 
       int nLoc;   //stored in stack? 
       string str = "mystring"; //stored in stack? 
       .. 
       if(CONDITION) 
       { 
        static int nSIf; //stored in static area of memory 
        int loopvar;  //stored in stack 
        .. 
       } 
      } 
} 

int main(int) 
{ 
    Foobar bar; //bar stored in stack? or a part of it? 

    Foobar *pBar; //pBar is stored in stack 

    pBar = new Foobar(); //the object is created in heap? What part of the object is stored on heap 

} 

EDIT:
gì confuses me là, nếu pBar = new Foobar(); lưu trữ các đối tượng trên heap, làm thế nào mà int nLoc;int pubVar;, đó là những thành phần của đối tượng được lưu trữ trên stack? Âm thanh mâu thuẫn với tôi. Chẳng lẽ tuổi thọ của pubvarpBar có giống nhau không?

+0

Ý tưởng tốt nhất là ngừng suy nghĩ về đống và ngăn xếp. Chúng không thực sự tồn tại trong C++ (một cấu trúc Java/C#) của nó. Suy nghĩ về tuổi thọ (duration) của một đối tượng. –

+2

Waitaminute. Ngăn xếp là một cấu trúc Java? Chắc chắn không phải. Đó là một cấu trúc C, nếu không lớn hơn. Nhưng 'setjmp/longjmp' làm cho nó rất rõ ràng rằng C có một chồng. Java mặt khác cho phép các đối tượng thoát khỏi phạm vi chức năng, đó là lý do tại sao khái niệm ngăn xếp không tồn tại (bộ nhớ wrt; ngoại lệ là một vấn đề khác) – MSalters

Trả lời

10

"Heap" và "stack" bị outmoded, các cụm từ không chính xác và khó hiểu liên quan đến thời lượng lưu trữ.

Đối tượng có "thời lượng lưu trữ tự động" là những gì ngớ ngẩn mà mọi người gọi là "đối tượng ngăn xếp". Chúng là những cái mà bạn sẽ định nghĩa bên trong một hàm là "biến cục bộ". Họ đi ra khỏi phạm vi khi khối kèm theo của họ kết thúc.

Đối tượng với "thời gian lưu trữ năng động" là những người mà bạn tạo trên cửa hàng miễn phí với sự trợ giúp của từ khóa new (hoặc, nếu bạn là ngớ ngẩn, malloc), và sau đó phá hủy bất cứ khi nào bạn thích với các từ khóa delete (hoặc nếu bạn ngớ ngẩn, free).

Ngoài ra còn có các đối tượng có "thời lượng lưu trữ tĩnh" tuân theo tất cả các loại quy tắc kỳ lạ về thứ tự khởi tạo và mọi thứ. Chúng tôi có xu hướng không sử dụng chúng trong C++ thành ngữ nhiều như chúng tôi có thể giúp nó.

Đối với các biến cụ thể trong ví dụ mã của bạn, nhận xét của bạn đều chính xác, bất chấp sự thất bại trong thuật ngữ.

Phụ Lục:

Các thuật ngữ "đống" và "chồng" là lỗi thời, liên quan đến sao khi các thư viện runtime phổ biến nhất được sử dụng những cấu trúc dữ liệu để lưu trữ các đối tượng mà đã dynamically- và tự động phân bổ, tương ứng (các đối tượng được phân bổ tĩnh phù hợp với cả hai loại, ngẫu nhiên).

Những ngày này không phải lúc nào cũng đúng, và chắc chắn không được bắt buộc bởi tiêu chuẩn C++, điều này không quan tâm nơi mọi thứ được lưu trữ. Nó chỉ quan tâm đến cách chúng được tạo ra và phá hủy, và khoảng thời gian chúng sống.

+1

Trên thực tế, lưu ý rằng các thành viên lớp có thời lượng tự động có thể không nằm trên "(nếu như một điều thậm chí tồn tại), nếu lớp đóng gói được phân bổ trên" đống "(nếu một điều như vậy thậm chí tồn tại). Một ví dụ khác về lý do tại sao bạn không nên sử dụng các điều khoản này. –

+1

Tôi nghĩ n và pubVar được lưu trữ trong heap, như là một phần của đối tượng container. – Ariel

+1

@Ariel: Nếu việc triển khai sử dụng một đống, thì có trong trường hợp này các thành viên sẽ xảy ra trên "đống" đó vì đối tượng là. Mặc dù vậy, C++ không có kiến ​​thức về điều đó. –

5

Tôi đã cập nhật chú thích của bạn với những gì tôi tin là chính xác hơn. Lưu ý rằng Tomalak đúng là 'stack' và 'heap' không được chỉ định theo tiêu chuẩn, và các cơ chế khác với một ngăn xếp có thể được sử dụng để chuyển các tham số để lưu các biến tự động. Tuy nhiên, tôi vẫn sử dụng các thuật ngữ này vì chúng thực sự được sử dụng khá thường xuyên trong việc triển khai trình biên dịch, các thuật ngữ ít nhiều được hiểu rõ (hoặc dễ hiểu), và tôi nghĩ họ vẫn minh họa thực tế những gì bạn quan tâm biết.

class Foobar 
{ 
     int n; //Stored wherever the current object is stored 
      // (might be static memory, stack or heap depending 
      // on how the object is allocated) 

     public: 

      int pubVar; //Stored wherever the current object is stored 
         // (might be static memory, stack or heap depending 
         // on how the object is allocated) 

      void foo(int param) //param stored in stack or register 
      { 
       int *pp = new int; //int is allocated on heap. 
       n = param; 
       static int nStat; //Stored in static area of memory 
       int nLoc;   //stored in stack or register 
       string str = "mystring"; // `str` is stored in stack, however 
             // the string object may also use heap 
             // to manage its data 
       .. 
       if(CONDITION) 
       { 
        static int nSIf; //stored in static area of memory 
        int loopvar;  //stored in stack or register 
        .. 
       } 
      } 
} 

int main(int) 
{ 
    Foobar bar; //bar stored in stack 

    Foobar *pBar; //pBar is stored in stack 

    pBar = new Foobar(); //the object is created in heap. 
          // The non-static data members are stored in that 
          // memory block. 

} 
+1

Thật không rõ ràng và khó hiểu. Nó cũng có thể là trường hợp "hầu hết mọi người" sử dụng chúng theo cách này, nhưng đó không phải là một lý lẽ để tránh sự mơ hồ. "Hầu hết mọi người" nghĩ rằng Sydney là thủ đô của Úc; mà không theo bất kỳ cách nào làm cho nó đúng. –

+0

+1 Giải thích tuyệt vời, chi tiết, có phương pháp. – templatetypedef

+0

@Micheal "tùy thuộc vào cách phân bổ đối tượng" không rõ ràng với tôi. Bạn có nghĩa là sự khác biệt sau đây: thanh Foobar; (// đối tượng được cấp phát trên stack) Foobar * pBar = new Foobar(); (// đối tượng này được cấp phát trên heap) – blitzkriegz

1

Tôi đồng ý với Tomalak,

C++ không quan tâm nơi mà mọi thứ đang lưu trữ.Nó chỉ quan tâm đến cách họ được xây dựng và phá hủy, và về thời gian họ sống.

Điều đó xảy ra, được thực hiện xác định, trình biên dịch có thể tối ưu hóa theo cách như vậy, bạn sẽ không có bất kỳ thứ gì được lưu trữ trên "ngăn xếp" khi bạn mong đợi. Cách phân bổ trên đống xảy ra được xác định bởi việc thực hiện mới/malloc hoặc một số chức năng của bên thứ ba (mới có thể gọi malloc).

gì rất có thể sẽ xảy ra trong ví dụ của bạn, là thế này:

Foobar bar; // bar will *most likely* be allocated on the "stack". 
Foobar *pBar; // pBar will *most likely* be allocated on the "stack". 
pBar = new Foobar(); // pBar will stay as is, and point to the location on the "heap" where your memory is allocated by new. 

Một vài điều mà bạn có thể tự hỏi về. Mảng kiểu C, như int array[5] không được lưu trữ giống như int* pointer= new int[5], trường hợp thứ hai rất có thể sẽ sử dụng nhiều bộ nhớ hơn vì nó không chỉ lưu trữ bộ nhớ cho mảng mà còn lưu trữ bộ nhớ trên ngăn xếp .

Hằng số tĩnh như 5"cake" thường được lưu trữ trong phần riêng biệt .DATA của tệp thi hành.

Điều quan trọng cần hiểu khi sử dụng C++, hầu hết những điều này được thực hiện xác định.

+0

Vì bạn nói * rất có thể *, có thể phân bổ/* thanh Foobar; */xảy ra trong heap? – blitzkriegz

+1

+1 vì phần lớn là đúng. –

+1

@Mahatma: Tuyệt đối. Phụ thuộc vào nơi bạn viết nó! BTW trên SO backticks có thể delimit mã mẫu và định dạng chúng cho bạn. –

0

Thành viên dữ liệu không phải là "bên trong" mỗi thể hiện của lớp đó: cho dù đó là trên ngăn xếp hoặc đống - hay ở nơi khác - không xác định bằng cách chỉ nhìn vào thành viên trong định nghĩa lớp. Nó không có ý nghĩa để nói về việc lưu trữ các thành viên dữ liệu không tĩnh mà không nói về việc lưu trữ cá thể của lớp mà chúng thuộc về.

struct A { 
    int n; // you cannot say n is always on the stack, or always on the heap, etc. 
}; 

int main() { 
    A a; // a is on the stack, so a.n is also on the stack 
    A *p = new A(); // *p, which means the object pointed to by p, is on the heap, 
        // so p->n is also on the heap 
        // p itself is on the stack, just like a 
    return 0; 
} 

A global; // global is neither on the stack nor on the heap, so neither is global.n 

"Ngăn xếp" là nơi các biến được gắn liền với tuổi thọ của một lời gọi hàm đơn; điều này còn được gọi là "thời lượng lưu trữ tự động". Có nhiều chiến lược phân bổ stack khác nhau và đáng chú ý là mỗi luồng có ngăn xếp riêng của nó - mặc dù đó là "ngăn xếp" phải rõ ràng từ ngữ cảnh. Có những điều thú vị xảy ra với ngăn xếp phân chia (cho phép phát triển và thu hẹp), nhưng trong trường hợp đó, nó vẫn là một ngăn xếp được chia thành nhiều phần.

"Vùng heap" chỉ là một từ khóa sai trong "giá trị" là "đống" chính, được sử dụng bởi malloc và các dạng khác nhau; điều này còn được gọi là "thời lượng lưu trữ động".

Biến toàn cục, thành viên dữ liệu tĩnh và thống kê cấp chức năng không thuộc về ngăn xếp cũng như vùng heap; còn được gọi là "thời gian lưu trữ tĩnh".

Các vấn đề liên quan