2011-12-20 51 views
12

Tôi là một chút mới đối với C++ và đang thực hiện lập trình trong Obj-C và Java cho đến bây giờ.C++: về quản lý bộ nhớ

Nói, tôi có một lớp:

class Person { 

private: 
    Wife *current_wife; 
    //..... 
}; 

Vì vậy obv tôi cần phải thực hiện một phương pháp setter để thay đổi biến dụ Vợ.

Như thế này:

Person::SetCurrentWife (Wife *new_wife) { 

    current_wife = new_wife; 
} 

Đó sẽ là một bản sao shalllow.

Vì vậy, ở đâu đó từ vòng lặp chính hoặc một cái gì đó tôi gọi:

Person *some_person = new Person(); 
... 
Wife *wife = new Wife(); 
some_person->SetCurrentWife(wife); 

Vì vậy, tôi đang bối rối: sẽ có một rò rỉ bộ nhớ đây? Tôi có nên xóa đối tượng vợ ở đây hoặc trong destructor của Person? Trong Obj-C tôi sẽ giải phóng người vợ hiện tại và sau đó gửi một thông điệp giữ lại cho vợ đối tượng ở trên, nhưng cách thích hợp để làm phương pháp setter trong C + + là gì?

+10

Vì bạn mới dùng C++, hãy lưu ý lời khuyên này: không bao giờ sử dụng 'mới',' xóa' hoặc con trỏ. Ngoại trừ, bạn * có thể * sử dụng 'mới' bên trong hàm tạo của con trỏ thông minh, nhưng chỉ sau khi bạn đã xác định rằng bạn thực sự yêu cầu bộ nhớ động. –

+4

Kerrek quên giới thiệu [một cuốn sách giới thiệu C++ tốt] (http://stackoverflow.com/q/388242/46642) :) –

+4

Trong OO bạn không obv cần một setter, bạn cần chức năng để cho đối tượng làm điều gì đó (ly hôn, tái hôn). Setters có thể được thuận tiện, họ không obv. – stefaanv

Trả lời

4

Bạn nên sử dụng con trỏ thông minh.

Nếu bạn sử dụng con trỏ thông thường, hãy thận trọng!

Bạn nên deletecurrent_wife thành viên cả trên trình hủy và phương thức đã đặt. Thiết lập một người vợ mới sẽ dẫn đến rò rỉ bộ nhớ của một tuổi, vì con trỏ đến bộ nhớ được cấp phát bị mất (trừ khi bạn quản lý bộ nhớ bên ngoài lớp - xem bên dưới).

Nhưng thậm chí làm như vậy, bạn cần đảm bảo rằng không ai ngoài lớp học có thể xóa thành viên. Bạn phải quyết định xem việc quản lý bộ nhớ có được để lại cho lớp hay được phân tán ra bên ngoài lớp học hay không và gắn bó với nó.

+3

-1 Bởi vì nó chỉ đơn giản là lời khuyên xấu. Tôi sẽ rất ngạc nhiên nếu con trỏ thông minh thực hiện ngữ nghĩa trọn đời mong muốn --- bạn thực sự không tin rằng vợ tôi sẽ không thể chết trước khi tôi làm (hoặc cái chết của tôi sẽ kích hoạt cô ấy), phải không? –

+0

@JamesKanze vậy tại sao đó lại là một vấn đề? Việc sử dụng con trỏ thông minh có hạn chế bạn xóa đối tượng vợ trước hoặc xóa nó sau khi người đó đã chết không? –

+0

nó phụ thuộc vào con trỏ thông minh, nhưng nếu bạn xóa một cái gì đó được quản lý bởi bất kỳ con trỏ thông minh tiêu chuẩn nào, bạn đang ở trong vùng hành vi không xác định. Nếu bạn sử dụng 'shared_ptr', đặc biệt, thời gian tồn tại của đối tượng nằm ngoài tầm tay bạn. –

1

con trỏ thông minh có thể giúp bạn

using boost::shared_ptr; // or std::shared_ptr, or std::tr1::shared_ptr or something like this 
class Person { 

private: 
    shared_ptr<Wife> current_wife; 
    //..... 
}; 

Person::SetCurrentWife (shared_ptr<Wife> new_wife) { 

    current_wife = new_wife; 
} 

Và bây giờ bạn không nên xóa bất kỳ người vợ nào cả.

shared_ptr<Person> some_person (new Person); 
... 
shared_ptr<Wife> wife (new Wife); 
some_person->SetCurrentWife(wife); 
+3

Điều này nghe giống như một công thức cho thảm họa. Chỉ có một vài trường hợp mà 'shared_ptr' hoạt động, và tôi nghi ngờ rằng đây không phải là một trong số chúng. Vì hai lý do: đầu tiên, có thể có 'Vợ 'cũng biết cô là vợ của ai, vì vậy bạn có chu kỳ (và bạn cần chu kỳ, vì nếu có chuyện gì xảy ra với' Vợ ', người phối ngẫu hiện tại phải được thông báo). Và thứ hai, cuộc đời của 'Vợ' chắc chắn không phụ thuộc vào cuộc đời của vợ chồng --- nếu 'Vợ chết ', cô ấy không nên sống sót chỉ vì vợ/chồng sẽ duy trì một con trỏ với cô ấy. –

+0

@JamesKanze đó là lý do tại sao có 'tăng :: weak_ptr' tôi đoán. Nó cho phép phá vỡ chu kỳ và thông báo an toàn của các đối tượng chết. – cheind

+0

@ChristophHeindl Vì vậy, con trỏ nào nên yếu, và con trỏ nào không? 'boost :: weak_ptr' là một hack, và nói chung không thể sử dụng được. –

7

Tùy thuộc vào những gì bạn đang cố gắng làm. Thứ nhất, như Kerrek SB có đã nhận xét, bạn không muốn sử dụng con trỏ nếu ngữ nghĩa giá trị có thể là được áp dụng: nếu Wife có thể sao chép và gán, hầu như không có lý do để phân bổ động. Trong trường hợp này, tuy nhiên, tôi đoán rằng Wife xuất phát từ Person (mặc dù có lẽ là một trang trí cho Person sẽ thích hợp hơn, vì thực tế là một trao Person ISA Wife có thể thay đổi theo thời gian), có thậm chí có thể các loại có nguồn gốc từ Wife (và rằng Person::current_wife có thể muốn giữ một trong số những điều này) và thực tế là, Wife có danh tính; bạn không muốn các bản sao của cùng một người vợ trên khắp nơi.

Nếu đúng như vậy, bạn thực sự phải xác định giao thức cho các tương tác của các lớp khác với Wife.Thông thường, tuổi thọ của Wife sẽ không phụ thuộc vào Person người giữ nó (mặc dù nếu nó là một trang trí , có thể), vì vậy Person chỉ nên giữ con trỏ đến nó, như bạn đã hoàn thành. Nhiều khả năng, các đối tượng Wife sẽ có chức năng khác nhau mà — ngầm hay rõ ràng — kiểm soát cuộc đời của mình: bạn có thể có cái gì đó như:

void Wife::die() 
{ 
    // ... 
    delete this; 
} 

ví dụ. Tuy nhiên, trong trường hợp đó, bất kỳ ai kết hôn với Wife sẽ phải được thông báo, để current_wife không trỏ đến một người phối ngẫu đã chết . Thông thường, một số biến thể của mẫu quan sát viên có thể được sử dụng cho điều này. (Lưu ý rằng bạn có chính xác cùng một vấn đề trong Java;.. Bạn không muốn Person::current_wife để trỏ đến một chết Wife Vì vậy, bạn muốn vẫn cần một hàm Wife::die(), và mô hình quan sát để thông báo cho người phối ngẫu )

trong những trường hợp như thế này (mà trong kinh nghiệm của tôi đại diện cho đa số của các đối tượng được cấp phát động trong C++), về sự khác biệt duy giữa C++ và Java là C++ có một cú pháp đặc biệt để gọi các “ destructor ”; trong Java, bạn sử dụng cú pháp gọi hàm thông thường, và bạn có thể cho hàm bất kỳ tên nào bạn muốn (mặc dù dispose dường như được sử dụng rộng rãi). Cú pháp đặc biệt cho phép trình biên dịch tạo mã bổ sung để giải phóng bộ nhớ, nhưng tất cả các hoạt động khác được kết hợp với thời gian kết thúc của đối tượng vẫn phải được lập trình (trong destructor, trong C++ — mặc dù trong trường hợp này, nó có thể có ý nghĩa khi đặt một số người trong số họ trực tiếp trong hàm Wife::die ).