2010-05-02 47 views
14

tôi nhận thấy rằng có hai cách để tạo ra C đối tượng ++:Tạo C++ đối tượng

BTree *btree = new BTree; 

BTree btree; 

Từ những gì tôi có thể nói, sự khác biệt duy nhất là trong cách đối tượng lớp được truy cập (so với -> toán tử) và khi cách đầu tiên được sử dụng, số nguyên riêng được khởi tạo thành 0.

Cách nào tốt hơn và sự khác biệt là gì?

Làm thế nào để bạn biết khi nào nên sử dụng cái này hay cái kia?

+3

Xem tại đây để biết thông tin về đống và ngăn xếp: http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap, http://stackoverflow.com/questions/ 408670/stack-static-và-heap-in-c –

Trả lời

0

Vâng, chúng được lưu trữ ở các vùng bộ nhớ khác nhau.

Dưới đây là thông tin tốt. Heap and Stack

+0

Tôi biết một chút về đống và ngăn xếp. Tại sao tôi quan tâm đến nơi nó được đưa vào? Khi nào tôi muốn nó trong đống, và khi nào tôi muốn nó trong ngăn xếp? – neuromancer

+0

Ngăn xếp bị giới hạn trong một ứng dụng. Heap không có giới hạn (không gian bộ nhớ ảo). Ngăn xếp cũng được giới hạn trong phạm vi của biến. Heap cho phép bạn vượt qua cấu trúc xung quanh bất kể phạm vi. –

+0

Tuyên bố này sai. Xin đừng bỏ qua bộ nhớ tĩnh. Ví dụ.câu lệnh 'BTree btree;' trong phạm vi toàn cục (hoặc không gian tên) tạo đối tượng trong bộ nhớ tĩnh, có thể có nhiều ý nghĩa, đặc biệt trong môi trường bị hạn chế về bộ nhớ (tất cả các ngôn ngữ được quản lý bộ nhớ tự động như Java * cough *) chúng tôi ..). – Frunsi

5

Biểu mẫu đầu tiên tạo đối tượng trên heap trong khi biểu mẫu thứ hai tạo đối tượng trên chồng.

Thứ hai từ sẽ bị hủy khi chức năng kết thúc chạy. Đầu tiên sẽ vẫn còn sống cho đến khi bị xóa cụ thể.

Biểu mẫu thứ hai là tốt nhất nếu bạn chỉ muốn sử dụng đối tượng trong phạm vi hiện tại. Bạn không cần phải lo lắng về việc loại bỏ nó bởi vì nó sẽ được thực hiện cho bạn. Cũng lưu ý rằng một số thư viện không hoạt động nếu có các lớp được tạo trên ngăn xếp.

Nếu đối tượng phải sống lâu hơn chức năng, biểu mẫu mới là tùy chọn tốt hơn.

32

Hai khác biệt:

  • họ tạo ra các đối tượng trong các phần khác nhau của bộ nhớ (đống vs stack)

  • đối tượng suốt đời là khác nhau: Trong trường hợp đầu tiên, mã quản lý cấp phát bộ nhớ một cách rõ ràng, và nó cũng phải quản lý thỏa thuận rõ ràng (sử dụng xóa/xóa []).

    Trong trường hợp thứ hai, đối tượng được tự động deallocated vào cuối phạm vi kèm theo của nó (hoặc là một phương pháp, một khối lồng nhau trong một phương pháp, hoặc một lớp)

Mà một trong những bạn sử dụng phụ thuộc chủ yếu trong suốt thời gian tồn tại của đối tượng (nếu nó phải tồn tại phương thức mà nó được tạo ra hay không).

+1

+1, tôi chỉ muốn thêm quy tắc đầu tiên và đơn giản: thích phân bổ tự động, sử dụng phân bổ rõ ràng khi được yêu cầu, ví dụ: ví dụ BAD: 'void foo() {BTree * btree = new BTree; btree-> DoSomething(); xóa btree; } ' – Frunsi

+0

Nếu đối tượng được khai báo trong chính, nó sẽ tự động được deallocated khi thoát chính cho cả hai phương pháp? – neuromancer

+0

Một đối tượng phân bổ heap (sử dụng 'mới') mà không bị xóa trước khi chương trình kết thúc sẽ không được" deallocated "cho mỗi se. Ví dụ, destructor của nó sẽ không được gọi là chương trình kết thúc. Tuy nhiên, bộ nhớ được sử dụng bởi đối tượng sẽ được trả về hệ điều hành. Không có cách nào mà một chương trình chạy dưới một hệ điều hành hiện đại có thể tiếp tục tiêu thụ bộ nhớ sau khi nó đã thoát, bất kể nó bị rò rỉ đến mức nào. –

2

Sự khác biệt cấp cao là đối tượng tuổi thọ. Ví dụ, nếu bạn đang viết một trò chơi video, bạn sẽ phân bổ các đối tượng tương ứng với quái vật trên heap, thông qua new. Bằng cách đó, đối tượng bên dưới của quái vật sống chính xác miễn là con quái vật, điều không thể biết được khi bạn viết chương trình. Khi người chơi giết quái vật, mã của bạn có thể phá hủy đối tượng quái vật bằng cách sử dụng delete.

Bộ đếm tổng số điểm, mặt khác, bạn sẽ sử dụng biểu mẫu khác, vì bạn biết bạn muốn bộ đếm ở lại bao lâu (có lẽ, miễn là trò chơi đang chạy!).Bằng cách đặt biểu mẫu đó trong "phạm vi toàn cầu" bên ngoài bất kỳ phần tử chức năng nào, nó sẽ được cấp phát tĩnh, như là một phần của chính chương trình nhị phân.

Cuối cùng, nếu bạn đã được tính toán tổng của một mảng, như thế này:

int mysum(int* arr, int len) { 
    int sum = 0; 
    for (int i = 0; i < len; ++i) { sum += arr[i] } 
    return sum; 
} 

biến sum được cấp phát trên stack, mà về cơ bản là những gì bạn muốn: một biến tạm thời mà bạn không phải giải quyết một cách rõ ràng, và chỉ xung quanh khi chức năng đó thực sự đang chạy.

3

Sự khác biệt giữa hai biểu mẫu này là thời gian lưu trữ cho các đối tượng đó được phân bổ. Biểu mẫu phân bổ tĩnh tên là BTree bTree; có phân bổ hoàn thành vào thời gian biên dịch - tức là trình biên dịch sẽ sắp xếp không gian bộ nhớ cho đối tượng này trong bộ nhớ khi chạy. Trong khi, phân bổ cho BTree *pbTree = new BTree, phân bổ động bị cáo buộc - thực hiện trong thời gian chạy - nghĩa là mẹ sẽ chỉ được phân bổ khi chương trình đang chạy đạt đến thời điểm này.

Trong trường hợp này, sự khác biệt giữa phân bổ tĩnh và động không rõ ràng. Hãy xem xét trường hợp sau đây bạn cần phân bổ không gian bộ nhớ cho một mảng số nguyên, nhưng số lượng phần tử chỉ có thể được xác định khi chạy, tức là chúng tôi chỉ có thể biết chính xác không gian bộ nhớ được sử dụng bởi mảng sau khi chương trình bắt đầu thực thi.

// in this function, we want to return a copy of the parameter array 
int *array_cpy(int *arr, int num){ 
    int *copy = new int[ num ]; 

    int i; 
    for(i = 0; i < num; i++){ 
     copy[ i ] = arr[ i ]; 
    } 

    return copy; 
} 

đây định nghĩa int copy[ num ]; là không thích hợp, một trong những lý do là cho những gì tôi đã nêu ở trên, còn lại là tuổi thọ của copy sống lâu hơn các chức năng. Tuy nhiên, VLA được cho phép trong đặc tả ngôn ngữ gần đây, lý do thứ hai là chìa khóa cho vấn đề này.

3

Trong việc lựa chọn giữa việc bạn nên xếp chồng hoặc đống phân bổ bộ nhớ, bạn cần phải đào một chút vào sự khác biệt giữa hai.

Có, bộ nhớ ngăn xếp có ưu điểm là được giải phóng tự động khi nó nằm ngoài phạm vi, mặc dù cùng có thể đạt được với con trỏ thông minh và phân bổ đống. Quan trọng hơn là những lý do đằng sau lý do tại sao điều này xảy ra.

Hiệu suất: Bộ nhớ ngăn xếp được làm sạch tự động vì nó liên quan đến việc chuyển đổi đơn giản của con trỏ ngăn xếp khi bộ nhớ nằm ngoài phạm vi. Vì lý do này, phân bổ và deallocation của bộ nhớ stack nhanh hơn nhiều so với bộ nhớ heap.

Thời gian sử dụng bộ nhớ: Bộ nhớ phân bổ heap có sẵn ngoài phạm vi của chức năng phân bổ. Stack không phải là. Sau khi điều chỉnh xung quanh lý luận của con trỏ ngăn xếp ở trên, một khi bộ nhớ được deallocated, nó là miễn phí và rất có thể sẽ được ghi đè cho việc phân bổ stack tiếp theo.

Tóm lại, sử dụng bộ nhớ ngăn xếp khi phân bổ tạm thời, đặc biệt nếu bạn cần phân bổ nhiều lần và hiệu suất là quan trọng. Sử dụng bộ nhớ heap khi đối tượng cần tồn tại ngoài phương thức phân bổ.

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