2012-04-14 35 views
32

Đoạn mã sau tạo một đối tượng trên stack:Tạo đối tượng trên ngăn xếp/heap?

Object o; 

Khi tạo một đối tượng trên heap chúng ta có thể sử dụng:

Object* o; 

o = new Object(); 

hơn:

Object* o = new Object(); 

Khi chúng tôi chia tay tạo đối tượng đống trên hai dòng và gọi hàm tạo trên dòng thứ hai (o = new object()), điều này có nghĩa là trong dòng đầu tiên ()) con trỏ đã được tạo trên ngăn xếp? Vì vậy, Object o đặt đối tượng trên ngăn xếp, trong khi Object* o đặt con trỏ đến một đối tượng trong tương lai trên ngăn xếp?

Câu hỏi thứ hai của tôi bao gồm nếu hai dòng mã được gọi bên ngoài một lớp. Gần đây tôi đã đọc (Global memory management in C in stack or heap?) rằng các biến toàn cầu không được chứa trên ngăn xếp/đống nhưng thực sự là một phần khác của bộ nhớ? Nếu đây là trường hợp, sẽ Object* o tạo một con trỏ sẽ nằm trong phần khác của bộ nhớ và nó trỏ đến đối tượng heap?

+0

Hai người đó sẽ * có thể * tối ưu hóa cho cùng một điều, tôi nghĩ vậy. – Ryan

+15

_pointer_ luôn được tạo trên ngăn xếp. – leftaroundabout

+1

Tôi sẽ đứng thứ hai @leftaroundabout, và đi xa hơn: tất cả các biến được khai báo trong một khối được tạo trên ngăn xếp; toàn bộ đối tượng cho ví dụ đầu tiên và con trỏ tới đối tượng trong đối tượng thứ hai. –

Trả lời

72

Trên thực tế, không có khai báo nói gì về đống hoặc chồng:

Object o; 

tạo ra một đối tượng với tự động lưu trữ có nghĩa là vị trí lưu trữ được xác định bởi bối cảnh trong đó các đối tượng được khai báo: Nếu mã đang ở trong một hàm, điều này xảy ra là ngăn xếp cuộc gọi. Nhưng dòng này cũng có thể là một thành viên của lớp hoặc, như bạn đã lưu ý, bên ngoài một hàm/lớp.

Để minh họa tại sao điều này là khác nhau:

struct Foo { 
    Object o; 
}; 

Foo* pf = new Foo(); 

Bây giờ đối tượng pf->o được tạo ra trên heap, không phải trên ngăn xếp, mặc dù (hay đúng hơn, ) nó có lưu trữ tự động.

Ngược lại,

Object* p; 

chỉ đơn giản là khai báo một con trỏ, không có gì hơn. Bộ nhớ của con trỏ không thể phân biệt được với bất kỳ đối tượng nào khác: nó có bộ nhớ tự động. Hơn nữa, biểu thức khởi tạo không ảnh hưởng đến bộ nhớ biến.

Điểm trỏ trỏ đến là vấn đề hoàn toàn khác. Nó có thể là một đối tượng phân bổ heap (sử dụng ví dụ new) hoặc nó có thể trỏ đến một đối tượng được cấp phát tự động khác. Xem xét:

Object o; 
Object* p = &o; 
+1

Bạn có thể giải thích ý nghĩa của "lưu trữ tự động" không? Ngoài ra, những gì sẽ là sự khác biệt giữa Foo pf = new Foo(); và Foo * pf = new Foo(); ? – user997112

+8

điều gì sẽ là sự khác biệt giữa Foo pf = new Foo(); và Foo * pf = new Foo(); - Thứ hai sẽ biên dịch, trong khi linh hồn thì không? – dasblinkenlight

+0

Bởi vì chúng tôi chỉ có thể sử dụng con trỏ liên quan đến phân bổ đống? – user997112

3

Hai biểu mẫu giống nhau với một ngoại lệ: tạm thời, (Object *) mới có giá trị không xác định khi tạo và gán riêng biệt. Trình biên dịch có thể kết hợp chúng lại với nhau, vì con trỏ không xác định không đặc biệt hữu ích. Điều này không liên quan đến các biến toàn cầu (trừ khi khai báo là toàn cầu, trong trường hợp đó nó vẫn đúng cho cả hai biểu mẫu).

1

Trong cả hai ví dụ của bạn, các biến cục bộ của loại Object* được phân bổ trên ngăn xếp. Trình biên dịch là miễn phí để sản xuất cùng một mã từ cả hai đoạn mã nếu không có cách nào để chương trình của bạn phát hiện sự khác biệt.

Khu vực bộ nhớ cho các biến toàn cục giống như vùng bộ nhớ cho các biến tĩnh - nó không nằm trong ngăn xếp cũng như trên vùng heap. Bạn có thể đặt các biến trong khu vực đó bằng cách khai báo chúng static bên trong hàm. Kết quả của việc làm như vậy là trường hợp trở thành được chia sẻ trong số các lời gọi đồng thời của hàm của bạn, vì vậy bạn cần phải xem xét cẩn thận đồng bộ hóa khi bạn sử dụng các số liệu thống kê.

Đây là a link để thảo luận về bố cục bộ nhớ của chương trình đang chạy C.

1

Một)

Object* o; 
o = new Object(); 

'' B)

Object* o = new Object(); 

Tôi nghĩ rằng A và B không có sự khác biệt. Trong cả hai trường hợp o là một con trỏ đến lớp Object. statement new Object() tạo một đối tượng của lớp Object từ bộ nhớ heap. Câu lệnh gán gán địa chỉ của bộ nhớ được cấp phát cho con trỏ o.

Một điều tôi muốn đề cập đến là kích thước bộ nhớ được phân bổ từ heap luôn là sizeof (Object) không phải sizeof (Object) + sizeof (void *).

6

C++ cung cấp ba cách khác nhau để tạo các đối tượng:

  1. stack-based như đối tượng tạm thời
  2. Heap dựa trên bằng cách sử dụng mới
  3. cấp phát bộ nhớ tĩnh như biến toàn cục và namespace- đối tượng phạm vi

Xem xét trường hợp của bạn,

Object* o; 
o = new Object(); 

và:

Object* o = new Object(); 

Cả hai hình thức đều giống nhau. Điều này có nghĩa rằng một biến con trỏ o được tạo ra trên ngăn xếp (giả sử các biến của bạn không thuộc về 3 loại ở trên) và nó trỏ đến một bộ nhớ trong heap, chứa đối tượng.

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