Trong C++, khi nào tốt nhất để sử dụng ngăn xếp? Khi nào tốt nhất để sử dụng heap?Khi nào tốt nhất để sử dụng ngăn xếp thay vì heap và ngược lại?
Trả lời
Sử dụng ngăn xếp khi biến của bạn sẽ không được sử dụng sau khi hàm hiện tại trả về. Sử dụng vùng heap khi dữ liệu trong biến là cần thiết vượt quá tuổi thọ của hàm hiện tại.
Có nhiều cách để giải quyết vấn đề đó. Việc chuyển một bộ đệm tới một hàm mà sau đó ghi dữ liệu vào nó là một cách hay để có một hàm "trả về" dữ liệu động đang sống trong khung ngăn xếp thấp hơn. Nó ít giống OO hơn, nhưng nó hiệu quả hơn nhiều. –
Kích thước cũng là một xem xét: bất cứ điều gì trên 1K trên ngăn xếp nên được xem xét cẩn thận. Đôi khi tốt hơn để có một con trỏ ngăn xếp để bộ nhớ heap (cùng với 'Resource Acquisition là Initialization' thành ngữ) – Arkadiy
Nhưng những gì về khi bộ nhớ là một tài sản của một lớp học, làm thế nào để bạn quyết định khi một tài sản lớp phải là một con trỏ hay cách khác? Ngoài ra khi nào bạn có thể sử dụng một con trỏ thông minh? – JagWire
Sử dụng vùng đệm để chỉ phân bổ không gian cho các đối tượng trong thời gian chạy. Nếu bạn biết kích thước tại thời gian biên dịch, hãy sử dụng ngăn xếp. Thay vì trả về các đối tượng phân bổ heap từ một hàm, chuyển một bộ đệm vào hàm để nó ghi vào. Bằng cách đó, bộ đệm có thể được cấp phát nơi mà hàm được gọi là một mảng hoặc cấu trúc dựa trên ngăn xếp khác.
Ít báo cáo malloc() bạn có, ít cơ hội bị rò rỉ bộ nhớ hơn.
Câu hỏi này có liên quan (mặc dù không thực sự là lừa đảo) với số What and where are the stack and heap, đã được hỏi cách đây vài ngày.
Câu hỏi bị hình thành. Có những tình huống bạn cần ngăn xếp, những nơi khác bạn cần đống, những nơi khác bạn cần bộ nhớ tĩnh, những nơi khác bạn cần dữ liệu bộ nhớ const, những nơi khác bạn cần lưu trữ miễn phí.
Ngăn xếp nhanh, vì phân bổ chỉ là "gia tăng" trên SP và tất cả "phân bổ" được thực hiện tại thời điểm yêu cầu của hàm bạn đang ở. Phân bổ lưu trữ/phân bổ Heap (hoặc lưu trữ miễn phí) là nhiều thời gian hơn đắt tiền và dễ bị lỗi.
Theo quy tắc chung, tránh tạo các đối tượng lớn trên ngăn xếp.
- Tạo đối tượng trên ngăn xếp giải phóng bạn khỏi gánh nặng ghi nhớ để dọn dẹp (đọc xóa) đối tượng. Nhưng việc tạo quá nhiều đối tượng trên ngăn xếp sẽ làm tăng nguy cơ tràn ngăn xếp.
- Nếu bạn sử dụng heap cho đối tượng, bạn nhận được bộ nhớ nhiều mà hệ điều hành có thể cung cấp, lớn hơn nhiều so với chồng, nhưng sau đó lại phải đảm bảo giải phóng bộ nhớ khi bạn hoàn thành. Ngoài ra, việc tạo quá nhiều đối tượng quá thường xuyên trong vùng heap sẽ có xu hướng phân mảnh bộ nhớ, do đó sẽ ảnh hưởng đến hiệu suất của ứng dụng của bạn.
Sử dụng ngăn xếp khi bộ nhớ đang được sử dụng được giới hạn nghiêm ngặt đối với phạm vi bạn đang tạo. Điều này rất hữu ích để tránh rò rỉ bộ nhớ vì bạn biết chính xác nơi bạn muốn sử dụng bộ nhớ, và bạn biết khi nào bạn không còn cần đến bộ nhớ nữa, do đó bộ nhớ sẽ được dọn dẹp cho bạn.
int main()
{
if (...)
{
int i = 0;
}
// I know that i is no longer needed here, so declaring i in the above block
// limits the scope appropriately
}
Vùng heap hữu ích khi bộ nhớ của bạn có thể được truy cập ngoài phạm vi tạo và bạn không muốn sao chép biến ngăn xếp. Điều này có thể cung cấp cho bạn kiểm soát rõ ràng về cách bộ nhớ được phân bổ và deallocated.
Object* CreateObject();
int main()
{
Object* obj = CreateObject();
// I can continue to manipulate object and I decide when I'm done with it
// ..
// I'm done
delete obj;
// .. keep going if you wish
return 0;
}
Object* CreateObject()
{
Object* returnValue = new Object();
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn't go away, its passed back using
// a pointer
}
Rõ ràng là một vấn đề phổ biến ở đây là bạn có thể quên xóa đối tượng của mình. Điều này được gọi là rò rỉ bộ nhớ. Những vấn đề này phổ biến hơn khi chương trình của bạn trở nên ít hơn và ít tầm thường hơn khi "quyền sở hữu" (hoặc người chính xác chịu trách nhiệm xóa mọi thứ) trở nên khó xác định hơn.
Các giải pháp phổ biến trong nhiều ngôn ngữ được quản lý hơn (C#, Java) là triển khai bộ sưu tập rác để bạn không phải suy nghĩ về việc xóa mọi thứ.Tuy nhiên, điều này có nghĩa là có gì đó trong nền chạy theo định kỳ để kiểm tra dữ liệu heap của bạn. Trong một chương trình không tầm thường, điều này có thể trở nên khá kém hiệu quả khi luồng "thu gom rác" bật lên và chuồn đi, tìm kiếm dữ liệu sẽ bị xóa, trong khi phần còn lại của chương trình của bạn bị chặn thực thi.
Trong C++, giải pháp phổ biến nhất và tốt nhất (theo ý kiến của tôi) để xử lý rò rỉ bộ nhớ là sử dụng con trỏ thông minh. Phổ biến nhất trong số này là boost::shared_ptr là (reference counted)
Vì vậy, để tạo lại ví dụ trên tăng :: shared_ptr CreateObject();
int main()
{
boost::shared_ptr<Object> obj = CreateObject();
// I can continue to manipulate object and I decide when I'm done with it
// ..
// I'm done, manually delete
obj.reset(NULL);
// .. keep going if you wish
// here, if you forget to delete obj, the shared_ptr's destructor will note
// that if no other shared_ptr's point to this memory
// it will automatically get deleted.
return 0;
}
boost::shared_ptr<Object> CreateObject()
{
boost::shared_ptr<Object> returnValue(new Object());
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn't go away, its passed back to
// the receiving shared_ptr, shared_ptr knows that another reference exists
// to this memory, so it shouldn't delete the memory
}
Và sau đó có di chuyển-ngữ nghĩa –
làm quy tắc sử dụng ngón tay cái bất cứ khi nào bạn có thể. tức là khi biến không bao giờ cần ngoài phạm vi đó.
nhanh hơn, ít bị phân mảnh hơn và sẽ tránh các chi phí khác liên quan đến việc gọi điện thoại malloc hoặc mới. phân bổ tắt của ngăn xếp là một vài hoạt động lắp ráp, malloc hoặc mới là hàng trăm dòng mã trong một thực hiện hiệu quả.
không bao giờ tốt nhất để sử dụng heap ... không thể tránh khỏi. :)
Nó tốt hơn so với một vài hoạt động lắp ráp - nó chỉ là một cộng hoặc trừ (tùy thuộc vào hướng chồng của bạn phát triển). – Eclipse
cộng và trừ không phải lúc nào cũng là đơn lẻ ... mà còn xem xét việc dọn dẹp ở đầu bên kia. tùy thuộc vào quy ước cuộc gọi sẽ có một phụ/thêm để phù hợp với add/sub mặc dù tất cả những điều này có thể được kết hợp tùy thuộc vào cách bạn sử dụng stack và những gì tối ưu hóa trình biên dịch thực hiện (nó thực sự có thể đun sôi xuống để hướng dẫn bằng không. .. hoặc trong trường hợp rất đặc biệt, chỉ dẫn trừ đi) – jheriko
Một ngoại lệ cho quy tắc nêu trên mà bạn thường nên sử dụng ngăn xếp cho các biến địa phương mà không cần thiết bên ngoài phạm vi của hàm:
chức năng đệ quy có thể làm cạn kiệt không gian ngăn xếp nếu họ phân bổ lớn địa phương biến hoặc nếu chúng được gọi đệ quy nhiều lần. Nếu bạn có một hàm đệ quy sử dụng bộ nhớ, có thể là một ý tưởng tốt để sử dụng bộ nhớ dựa trên heap thay vì bộ nhớ dựa trên ngăn xếp.
- 1. Làm cách nào để tạo một mảng trong C++ trên heap thay vì ngăn xếp?
- 2. Khi nào tôi nên sử dụng NSURL thay vì NSString và ngược lại?
- 3. Khi nào tôi nên sử dụng các mẫu thay vì thừa kế và ngược lại?
- 4. Tại sao bạn muốn phân bổ bộ nhớ trên heap thay vì ngăn xếp?
- 5. mới trên ngăn xếp thay vì heap (như alloca vs malloc)
- 6. Chức năng nào là tốt nhất về hiệu quả sử dụng ngăn xếp và thời gian
- 7. Đảo ngược ngăn xếp bằng Python sử dụng đệ quy
- 8. Tạo đối tượng trên ngăn xếp/heap?
- 9. Địa chỉ của Ngăn xếp và Heap trong C++
- 10. C++ Phân bổ bộ nhớ trên heap và ngăn xếp?
- 11. Khi nào tôi nên sử dụng UIImagePickerControllerSourceTypePhotoLibrary thay vì UIImagePickerControllerSourceTypeSavedPhotosAlbum?
- 12. Bắt trái và phải nổi để chồng lên nhau thay vì ngăn xếp
- 13. Khi nào tôi nên sử dụng UserControl thay vì Trang?
- 14. Tràn ngăn xếp khi sử dụng mô hình System.Net.Sockets.Socket.AcceptAsync
- 15. Khi nào sử dụng HttpApplicationState thay vì Web.Caching.Cache?
- 16. OpenMP: hiệu suất kém của mảng heap (mảng ngăn xếp hoạt động tốt)
- 17. GCC - Cách sắp xếp lại ngăn xếp?
- 18. Khi nào nên sử dụng zip thay vì izip?
- 19. Cách tốt nhất để chuyển đổi XPS thành PDF (và ngược lại)?
- 20. Proxy ngược lại tốt nhất cho IIS 6?
- 21. NSString @property, sử dụng bản sao thay vì giữ lại
- 22. Làm thế nào để ngăn chặn hợp nhất từ cột sắp xếp lại
- 23. khi nào nên sử dụng index.php thay vì index.html
- 24. Khi nào sử dụng Float32Array thay vì Array trong JavaScript
- 25. Cách chuyển đổi tốt nhất một dấu vết ngăn xếp thành HTML (sử dụng .NET - C#)
- 26. Ngăn xếp SIP Java tốt nhất là gì?
- 27. Android onConfigurationChanged: làm thế nào để lưu và khôi phục lại phân đoạn ngăn xếp?
- 28. Vùng chứa heap Java có bao gồm ngăn xếp luồng
- 29. Sử dụng ngăn xếp không đổi
- 30. Palindrome Sử dụng ngăn xếp
Tôi giả sử bạn có nghĩa là ngăn xếp hệ thống và đống hệ thống để cấp phát bộ nhớ, không phải cấu trúc dữ liệu đống và ngăn xếp, đúng không? –