2009-06-14 52 views
15

Tôi đã học được một cách đau đớn trong vài ngày qua rất nhiều về lập trình bằng C++.
Tôi thích nó :)
Tôi biết tôi nên giải phóng bộ nhớ - quy tắc "mỗi malloc = miễn phí" hoặc "mỗi mới = xóa" hiện có trong thế giới của tôi, nhưng tôi đang sử dụng chúng cho các đối tượng khá đơn giản.
Còn vectơ thì sao? Bất cứ nơi nào tôi có thể, tôi đang sử dụng vector.clear() nhưng điều đó rõ ràng là không đủ, bởi vì tôi đang có rò rỉ bộ nhớ rất lớn.
Bạn có thể hướng dẫn tôi cách tôi nên đối xử với điều này không?Tôi có nên xóa vector <string> không?

* Chỉnh sửa
Cảm ơn, nhận xét của bạn đã làm cho tôi nghĩ về alghorithm của ứng dụng này và tôi sẽ có thể loại bỏ hoàn toàn vectơ. : O
Xin lỗi - Tôi đã bắt đầu giải thích trường hợp sử dụng của tôi ở đây là gì và tôi đã tìm ra những gì tôi thực sự cần. Nó giống như khi bạn mã 3 ngày qua trong 18 giờ một ngày: | * Chỉnh sửa 2
Điều này thật điên rồ. Bởi những thay đổi nhỏ trong mã, tôi đã loại bỏ việc sử dụng bộ nhớ từ 2x130 mb (liên tục phát triển) thành 2x13,5mb, kích thước không đổi. Cảm ơn vì đã khiến tôi suy nghĩ về điều đó theo một cách khác.

Btw. tự đánh giá mã như vậy có một cái tên - ai cũng nhớ điều đó? Đó là khi bạn hỏi bất kỳ ai (kể cả mẹ hoặc chó) và bắt đầu giải thích vấn đề của bạn là gì - và đột nhiên bạn giải quyết vấn đề 5 giờ này, chỉ bằng cách cố gắng nhìn nó từ quan điểm khác, hoặc chỉ bằng cách cố gắng tóm tắt tất cả về. Tôi thường thấy mình bị bắt trên đó ...

+5

Vì bạn mới dùng quản lý bộ nhớ, có lẽ bạn có thể giải thích cách bạn biết mình đang bị rò rỉ bộ nhớ. Một số cách đo rò rỉ bộ nhớ không thực sự phản ánh những gì đang diễn ra. –

+0

Bạn có thể muốn đăng một số mã mẫu về cách bạn đang sử dụng lớp vectơ. Ví dụ, bạn có vectơ của con trỏ đến các đối tượng được tạo động không? –

+0

tốt, tôi chỉ đơn giản thấy rằng việc thực hiện kết quả ứng dụng của tôi ngày càng chiếm nhiều bộ nhớ. Tôi đang thực hiện các hoạt động khá dễ dàng (làm cho băm md5 trong 2 quy trình, gắn với mpcih2), cho thử nghiệm của tôi chính xác là 25 triệu hoạt động. Một quá trình gửi đến các gói dữ liệu khác (chuỗi) và thứ hai tính toán băm cho điều đó. Vào cuối của thực hiện, tôi có 2x 130 mb thực hiện. Đó là cách quá nhiều để được bình thường. – IamDeveloper

Trả lời

19

Quy tắc là khi bạn xóa một vectơ của các đối tượng, hàm hủy của mỗi phần tử sẽ được gọi. Mặt khác, nếu bạn có vectơ con trỏ, vector::clear() sẽ không gọi số delete trên chúng và bạn phải tự xóa chúng.

Vì vậy, nếu tất cả những gì bạn có là một vectơ của chuỗi và không phải là con trỏ tới chuỗi, thì rò rỉ bộ nhớ của bạn phải do một thứ khác gây ra.

+0

Điều đó có áp dụng chung không? Nếu tôi có một lớp có 'std: vector' là một trong những thuộc tính của nó, thì C++ sẽ gọi hàm hủy đó khi lớp bị hủy? –

+4

Có. Khi một đối tượng bị phá hủy, hàm hủy của tất cả các thành viên dữ liệu của nó được gọi. Nhưng như tôi đã nói, hãy nhận biết những gì bạn đang lưu trữ trong vectơ. Nếu nó là một vectơ của các đối tượng, các đối tượng sẽ bị phá hủy cùng với vectơ. Nếu nó là một vectơ của con trỏ, thì bạn phải tự xóa chúng. – Dima

7

Gọi v.clear() sẽ hủy tất cả các đối tượng hiện đang được giữ bên trong v, nhưng nó sẽ không giải phóng bộ nhớ (giả định rằng vectơ sẽ sớm được điền lại).

Nếu bạn thực sự muốn giải phóng bộ nhớ, thành ngữ là

vector<string>().swap(v); 

này sẽ tạo ra một (tạm thời) vector mới và trao đổi nội dung của nó với v. Vector tạm thời sau đó bị phá hủy, giải phóng bộ nhớ cùng với nó.

+0

Bây giờ tôi thấy ý định đằng sau điều đó, nhưng có vẻ khá khó xử với tôi. Và nó sẽ giống như v.swap (vector ())? – ypnos

+2

Nó có vẻ khó xử, nhưng nó là cách thành ngữ để giảm 'v.capacity()'. Đoạn mã của bạn sẽ không biên dịch, vì 'vector ()' là một giá trị và không thể bị ràng buộc với tham chiếu không phải const. – avakar

+0

Để làm rõ: trong a.swap (b), a và b không bằng nhau. Hoán đổi thành viên có một đối số, một tham chiếu không phải const. Bạn có thể gọi các hàm không phải là thành viên của các trạng thái tạm thời, vì vậy trong a.swap (b), một hàm có thể là tạm thời. Nhưng b là ràng buộc với tham chiếu không const và không thể là tạm thời. – MSalters

4

Các vector (giống như tất cả các container tiêu chuẩn) sở hữu các đối tượng bên trong nó.
Vì vậy, nó có trách nhiệm phá hủy chúng.

Lưu ý: Nếu vectơ của bạn chứa con trỏ thì nó sẽ sở hữu con trỏ (không phải con trỏ trỏ vào). Vì vậy, những cần phải được xóa. Nhưng có những cách dễ dàng hơn.

Bạn có thể sử dụng vectơ con trỏ thông minh. Trong thực tế, bạn nên sử dụng một số hình thức của con trỏ thông minh cho gần như tất cả mọi thứ.Nếu bạn đang sử dụng con trỏ, có lẽ bạn vẫn đang lập trình như một lập trình viên C.

Vì vậy:

std::vector<int> data; // clear is fine. 

std::vector<int*> data1; // Now things need to be deleted. 
// alternative 1: 
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto 
              // delete the pointer. 
// alternative 2: 
boost::ptr_vector<int> data3;    // Here the container knows that 
              // it is holding pointers and will 
              // auto de-reference them when you 
              // its members. 

Nhưng có vẻ như bạn cần phải bắt đầu suy nghĩ về tìm hiểu về con trỏ thông minh.

int* x = new int(5); 
// Do stuff. 
*x = 8; 
delete x; 

// --- Instead use a smart pointer: 
std::auto_ptr<int> x(new int(5)); 
// Do stuff. 
*x = 8; 
// No delete (the auto ptr handles it. 
5

Xóa các phần tử khỏi vùng chứa STL được đảm bảo để gọi hàm hủy trên các thành phần này. Tuy nhiên, nếu bạn có một thùng chứa một số loại pointer-to-T, thì bạn vẫn phải giải phóng bộ nhớ chỉ vào chính mình (trong trường hợp này, "destructor" cho con trỏ được gọi, đó là không hoạt động).

Nếu bạn không muốn quản lý bộ nhớ theo cách thủ công trong trường hợp này, hãy xem xét sử dụng smart-pointer solution hoặc pointer container.

7

Bạn không cần phải thực hiện việc này. std :: string tự làm sạch, vì vậy các chuỗi không phải là vấn đề của bạn. Hãy nhớ rằng BẠN đã không sử dụng new để BẠN không phải sử dụng delete.

Bạn có thể nên tìm hiểu về RAII - nó giúp phân bổ và deallocation đơn giản hơn nhiều. Bạn sẽ tránh rò rỉ bộ nhớ theo cách này.

1

Nếu bạn có vectơ và nó nằm ngoài phạm vi, tất cả các đối tượng trong vectơ sẽ bị hủy. Không có thực sự cần phải gọi rõ ràng() trừ khi bạn muốn đổ các nội dung và tái sử dụng các vector. Tuy nhiên nếu bạn có cơ hội sử dụng một thứ gì đó giống như một vector thì hàm hủy của các đối tượng được trỏ đến sẽ không được gọi là hủy hoại véc tơ không tuân theo các chỉ số được biểu diễn bởi các con trỏ.

Tất cả những gì đã nói, bạn có thực sự xác nhận rằng bạn đã bị rò rỉ bộ nhớ chính hãng và chúng có phải do dữ liệu trong vectơ gây ra không?

0

Như đã đề xuất, hãy sử dụng RAII.

Đó là một nguyên tắc hay để không bao giờ đặt mới và xóa cuộc gọi vào luồng mã chính của bạn. Luôn luôn cố gắng để đưa chúng vào các đối tượng để các đối tượng destructor có thể giải phóng những gì cần phải được giải phóng. Bằng cách này, bạn tránh cần phải nhớ để gọi xóa và nó làm cho mã ngoại lệ của bạn an toàn (giả sử rằng bạn làm cho hoạt động của đối tượng của bạn ngoại lệ an toàn). Ví dụ, nếu bạn có một vectơ con trỏ tới chuỗi STL hoặc các mảng ký tự kiểu C, hãy đặt nó vào một StringContainer (sử dụng một tên tốt hơn) và có StringContainer giữ một vectơ và trong StringContainer destructor chạy một cho vòng lặp để xóa từng chuỗi trong vectơ.

Bạn có thể làm cho véc tơ bên trong StringContainer thành viên công cộng và lộn xộn xung quanh nó trực tiếp, nhưng nó thậm chí còn tốt hơn để thiết kế riêng tư hoặc được bảo vệ và thêm một số chức năng thành viên để quản lý chuỗi * vector.

Vì vậy, chương trình C++ chính của bạn sẽ không bao giờ thấy một chương trình mới hoặc xóa ở bất kỳ đâu. Thay vào đó, nó sẽ có rất nhiều đối tượng được phân bổ stack, auto_ptrs và shared_ptrs.

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