Từ những gì tôi hiểu, trong tiêu chuẩn C++ bất cứ khi nào bạn sử dụng toán tử mới, bạn cũng phải sử dụng toán tử xóa tại một số điểm để tránh rò rỉ bộ nhớ. Điều này là do không có bộ sưu tập rác trong C++. Trong bộ sưu tập rác .NET là tự động vì vậy không cần phải lo lắng về việc quản lý bộ nhớ. Tôi hiểu có đúng không? Cảm ơn.Tự động thu gom rác trong tiêu chuẩn C++?
Trả lời
Câu trả lời dài để nó là cho mỗi lần new
được gọi là, nơi nào đó, bằng cách nào đó, delete
phải được gọi, hoặc một số chức năng deallocation khác (phụ thuộc vào bộ cấp phát bộ nhớ vv)
Nhưng bạn không cần phải là người cung cấp cuộc gọi delete
:
- Có thu gom rác thải cho C++, dưới dạng Hans-Boehm Garbage Collector. Ngoài ra còn có các thư viện thu gom rác khác.
- Bạn có thể sử dụng con trỏ thông minh, sử dụng RAII (và tính tham chiếu nếu con trỏ cho phép truy cập chia sẻ) để xác định thời điểm xóa đối tượng. Một thư viện con trỏ thông minh tốt là số smart pointer của Boost. Con trỏ thông minh trong phần lớn các trường hợp có thể thay thế con trỏ thô.
- Một số khung ứng dụng, như Qt, xây dựng cây đối tượng, sao cho có mối quan hệ cha mẹ con cho các đối tượng được cấp phát của khung công tác.Kết quả là, tất cả là cần thiết cho một
delete
để được gọi trên một đối tượng, và tất cả các con của nó sẽ tự động đượcdelete
d là tốt.
Nếu bạn không muốn sử dụng bất kỳ kỹ thuật nào trong số này, để bảo vệ chống lại rò rỉ bộ nhớ, bạn có thể thử sử dụng công cụ kiểm tra bộ nhớ. Valgrind đặc biệt tốt, mặc dù nó chỉ hoạt động trên Linux
Đối với .NET, có, phân bổ bằng cách sử dụng gcnew
có nghĩa là bộ nhớ được theo dõi bởi .NET, do đó không có rò rỉ. Tuy nhiên, các tài nguyên khác, như xử lý tệp vv không được quản lý bởi GC.
Một trong những lợi thế (!) Của RAII là bạn có thể quản lý tài nguyên khác với bộ nhớ, ví dụ: xử lý tệp. Xóa đối tượng, và thì cũng là tập tin thuộc sở hữu của đối tượng được đóng lại. – casualcoder
Đừng quên về SBRM trong khi chúng tôi đang ném xung quanh từ viết tắt. ví dụ như fstream sẽ tự động đóng tệp khi nó nằm ngoài phạm vi. Cũng nên nhớ rằng các biến thành viên có một phạm vi của tuổi thọ của đối tượng cha, điều này làm cho SBRM rất thuận tiện ngay cả khi không có một destructor. – joshperry
Tôi nghĩ rằng SBRM bạn đề cập đến cho fstream là RAII. – blwy10
Chính xác bạn phải lo lắng về việc thu gom rác thải trên C++.
Và ... có no need to worry about garbage collection on .NET.
Chỉ khi bạn có các tập lệnh dài và chuyên sâu mà bạn cảm thấy cần tối ưu hóa, bạn có cần tập trung vào điều đó không.
Chỉnh sửa: Cả nhận xét của asveikau và Pavel Minaev đều rất tuyệt vời! Tôi đã quá mức để truyền tải thông điệp.
Tôi sẽ không nói hoàn toàn rằng bạn "không phải lo lắng về nó". Đối với một số loại đối tượng, bạn _do_ cần phải cẩn thận để thực hiện dọn dẹp thủ công, ngay cả trong C#. Ví dụ, bạn nên chắc chắn đóng các tập tin, và không dựa vào GC để làm điều đó cho bạn. – asveikau
Và, tất nhiên, không có gì ngăn bạn phân bổ bộ nhớ không được quản lý trong C# (hoặc ngôn ngữ .NET khác), mà sau đó bạn phải tự giải phóng. Xem 'Marshal.AllocHGlobal' vv –
"không có bộ sưu tập rác trong C++".
đúng.
Không đúng sự thật. Có sẵn những người thu gom rác. (Và nó không phải là khó để xây dựng của riêng bạn). –
"có sẵn" hoặc "một tính năng tiêu chuẩn của ngôn ngữ?" Câu hỏi đặt ra là về các tính năng tiêu chuẩn của ngôn ngữ. Không có sẵn. Smart Pointers (IMO) là điều cần thiết, nhưng không phải là một tính năng tiêu chuẩn của ngôn ngữ. –
Bạn có thể sử dụng C++ với .NET theo hai cách: được quản lý hoặc không được quản lý. Trong chế độ được quản lý, bộ sưu tập rác của .NET sẽ xử lý việc giải phóng bộ nhớ thay cho bạn; trong chế độ không được quản lý, bạn gần gũi với hành vi bình thường/chuẩn của C++, vì vậy bạn phải tự chịu trách nhiệm về bộ nhớ của mình.
Bất kể "chế độ", mỗi 'new' là bộ nhớ không được quản lý và phải được deallocated bằng tay bởi' xóa'. C++/CLI thêm 'gcnew', nhưng đây không phải là C++ như vậy, mà là một phần mở rộng ngôn ngữ. –
Thực sự chúng ta đang nói về hai ngôn ngữ khác nhau. C++ và C++/CLI –
Có bạn đúng, theo chuẩn C++ (Trong C++ được quản lý hoặc các biến thể khác tùy thuộc) bạn phải sử dụng xóa sau mỗi lần mới. Trong C#, Java và các ngôn ngữ thu gom rác khác, điều này là không cần thiết (thực tế hầu hết chúng không tương đương với toán tử "delete").
thu gom rác thải tự động là hữu ích, nhưng bạn vẫn có thể nhận được rò rỉ bộ nhớ, như câu hỏi này cho thấy:
Nó được giảm trong .NET và Java, nhưng điều đó không có nghĩa là nó cho phép xấu mã hóa để được chăm sóc tự động. Vì vậy, trong C++ bạn cần phải giải thích rõ ràng những gì bạn yêu cầu, và tôi nghĩ rằng đôi khi tốt hơn, vì bạn biết những gì đang diễn ra. Tôi muốn trong .NET và Java rằng bộ thu gom rác đã làm ít trong chế độ gỡ lỗi, để giúp đảm bảo mọi người nhận thức được những gì họ đang làm.
Tuyên bố của bạn về toán tử mới hoàn toàn chính xác ... nhưng nó quá đơn giản hóa ngữ nghĩa C++ một chút.
Trong C++, các đối tượng có thể được tạo ra trên stack hay trên heap:
class Foo {};
int main() {
Foo obj1;
Foo* obj2 = new Foo();
delete obj2;
}
Trong ví dụ trên, obj1 được tạo ra trên stack và obj2 được tạo ra trên heap (với mới). Các đối tượng được tạo trên heap không bị hủy cho đến khi xóa được gọi rõ ràng trên chúng. Tuy nhiên, các đối tượng trên ngăn xếp sẽ tự động bị hủy khi chúng nằm ngoài phạm vi (ví dụ: khi hàm main() trả về trong ví dụ này).
Điều này cho phép thành phần "Khởi tạo tài nguyên đang khởi tạo" (a.k.a. RAII) bằng C++, mạnh hơn nhiều so với thu thập rác cơ bản. Các tài nguyên cần được dọn sạch (bộ nhớ heap, ổ cắm, tệp, kết nối DB, v.v.) thường được đặt trong các đối tượng dựa trên ngăn xếp có các trình phá hủy xử lý việc dọn dẹp.
Ngược lại, Java và C# không cho phép các đối tượng được xây dựng trên ngăn xếp, và không đảm bảo rằng bộ sưu tập sẽ xảy ra cũng như finalizers sẽ chạy (Tôi không phải là một C# guy, vì vậy tôi có thể là một ít sai lầm ở đó). Vì vậy, trong khi bạn nhận được quản lý bộ nhớ heap miễn phí trong Java/C#, bạn sẽ thực sự kết thúc với rất nhiều mã nguồn tài nguyên dọn dẹp trong các ngôn ngữ đó nhiều hơn bạn làm trong C++.
Trong idiomatic mức cao C++, bạn không bao giờ gọi xóa.
C++ không có bộ thu gom rác tiêu chuẩn hoạt động giống như trong C#, và do đó, về cơ bản, new
và delete
cần phải được ghép nối. Tuy nhiên, có các cơ chế trong C++ hoàn toàn loại bỏ việc sử dụng rõ ràng sử dụng delete
cho mã được viết theo phong cách hiện đại.
Điều đầu tiên cần lưu ý là trong C++ bạn sử dụng new
ít thường xuyên hơn hơn bạn sử dụng new
trong C#. Điều này là do trong C# bạn sử dụng new
bất cứ khi nào bạn tạo một thể hiện của một cấu trúc, lớp hoặc mảng, nhưng trong C++, bạn chỉ sử dụng new
khi bạn muốn quản lý một phần tử dữ liệu động. Hầu hết dữ liệu trong C++ không yêu cầu quản lý động và do đó có thể được tạo mà không cần sử dụng new
. [Nói cách khác, new
có ý nghĩa khác trong C# so với C++. Trong C++ nó chỉ rõ phân bổ động, trong khi trong C# nó được sử dụng cho bất kỳ công trình xây dựng nào.]
Thứ hai, bất cứ lúc nào bạn gọi new
trong C++, giá trị trả về phải được chuyển trực tiếp đến smart pointer. Con trỏ thông minh sẽ đảm bảo rằng delete
được tự động gọi cho bạn vào thời điểm thích hợp.
Nhân tiện, trừ khi bạn là một guru viết thư viện cấp thấp (hoặc học sinh học cách thực hiện điều này), bạn không bao giờ gọi new
để cấp phát một mảng trong C++. Thư viện chuẩn (và cũng là Boost/TR1) cung cấp các lớp mẫu phân bổ và quản lý các mảng cho bạn.
Tóm lại, C++ không sử dụng một nhà sưu tập rác nhưng nó có hình thức riêng của mình quản lý bộ nhớ tự động. Có những khác biệt tinh tế giữa hai cách tiếp cận, nhưng cả hai cách tiếp cận tự động hóa việc giải phóng bộ nhớ, do đó loại bỏ hầu hết các loại rò rỉ bộ nhớ.
Các cuộc biểu tình có thẩm quyền của các khái niệm được đưa ra bởi C++ tạo Bjarne Stroustrup trong câu trả lời cho câu hỏi: How do I deal with memory leaks?
Xem thêm:
- Dynamic memory management reference - con trỏ thông minh
- Containers library reference - mảng
Bởi cùng một mã thông báo, nếu bạn sử dụng xóa, nó có thể là một lỗi. Vấn đề là việc sử dụng xóa giả định rằng bạn biết chính xác cách thức luồng điều khiển của chương trình sẽ tiến hành sao cho việc xóa sẽ xảy ra vào thời điểm thích hợp. Đây là một cách dễ dàng, nhưng ngây thơ, giả định để thực hiện. Trước hết, nó đòi hỏi một số biện pháp cẩn thận để đúng vị trí hoạt động xóa. Quan trọng hơn, ngoại lệ thường có thể xảy ra ở bất kỳ điểm trung gian nào trong mã và vi phạm các giả định của bạn về luồng điều khiển. Sửa lỗi này với try/catch là có thể, nhưng nó không phải là "thực hành tốt nhất". – nobar
Trình diễn của Bjarne có phần ngày tháng, đặc biệt là việc anh ta sử dụng auto_ptr <> thường được choáng váng ngày nay (có những lựa chọn thay thế tốt hơn). Nhưng điều này chứng minh sự trưởng thành của cái mà trước đây tôi gọi là "phong cách hiện đại". Bjarne đã dạy cách tiếp cận này trong một thời gian dài. – nobar
Đây là một bài viết nói về cùng một điều nhưng chi tiết hơn về cơ học - bao gồm thảo luận về một số tính năng thư viện mới hơn: http://stackoverflow.com/questions/4963610/visual-c-native-memory-management- thực hành tốt nhất/4963633 # 4963633 – nobar
- 1. Buộc thu gom rác của mảng, C#
- 2. Thu gom rác trong Perl
- 3. Thu gom rác trễ?
- 4. Tiêu chí để kích hoạt thu gom rác trong .Net
- 5. Buộc thu gom rác thải
- 6. Khi nào để thu gom rác
- 7. đa và thu gom rác thải
- 8. đế và bộ thu gom rác Đi
- 9. Thu gom rác khi biên dịch sang C
- 10. JRuby - Cách khởi động bộ thu gom rác?
- 11. Thu gom rác của các chuỗi ký tự
- 12. Thông báo Thu gom Rác Bỏ lỡ
- 13. Khi nào bộ thu gom rác net hoạt động?
- 14. Thời gian thu gom rác cực dài
- 15. Ràng buộc Lua với C++ và thu gom rác
- 16. Thu gom rác - các nút gốc
- 17. Thu gom rác thủ công bằng Python
- 18. Tham khảo chéo và thu gom rác
- 19. Công cụ thu gom rác cho dalvik
- 20. Thông báo thu gom rác thải?
- 21. Bộ hẹn giờ có thể tự động thu gom rác không?
- 22. Thu gom rác Java G1 trong sản xuất
- 23. Khi nào đối tượng thu gom rác trong python?
- 24. Bộ thu gom rác có gọi là Dispose() không?
- 25. Cách thu gom rác thu thập các đối tượng tự tham chiếu?
- 26. Câu hỏi về Thu gom rác trong Java
- 27. Bộ thu gom rác nối tiếp của Java hoạt động tốt hơn nhiều so với các bộ thu gom rác khác?
- 28. Gcc 4.8.1 có hỗ trợ C++ 11 để thu gom rác không?
- 29. Python: hành vi thu gom rác thải với ctypes
- 30. Có thể ngừng thu gom rác thải .NET không?
Một trăm phần trăm chính xác! – henle
99,9% chính xác. Có những trường hợp bạn cần phải lo lắng về việc quản lý bộ nhớ trong .NET. – jmucchiello
trong C++/CLI bạn phân bổ bằng cách sử dụng 'gcnew' tuy nhiên bạn vẫn có thể sử dụng 'mới' nhưng sau đó chúng cần phải được ghép nối với 'xóa', giống như trong mã không được quản lý hoàn toàn. –