2013-10-16 16 views
6

Tôi biết có những câu hỏi tương tự nhưng không ai trong số họ đưa ra câu trả lời chính xác cho câu hỏi của tôi ...C++ Trả lại tài liệu tham khảo cho đối tượng mới

Cả hai điều này đều ổn? Hoặc tôi nên trở về một con trỏ? Và nếu không nên thay đổi cách thực hiện theo các phương pháp hay nhất.

Tôi muốn trả lại tham chiếu đến một đối tượng mới từ một hàm. Việc triển khai của tôi như sau:

MyClass& doSomething() { 
    return *(new MyClass()); 
} 

MyClass a = doSomething(); 

Điều này có ổn không vì một phiên bản mới của MyClass đang được cấp phát trên heap mới?

Hoặc tôi có nên làm cho nó không đổi (tôi thực sự không chắc chắn khi nào làm điều này hay không)?

const MyClass& doSomething() { 
    return *(new MyClass()); 
} 

Và nếu cả hai điều này là sai thì tôi chỉ cần trả lại con trỏ cho đối tượng mới?

Cảm ơn.

+0

Không cần thiết, tùy chọn đầu tiên là tốt. Ngoài ra, bạn cũng có thể trả lại con trỏ nếu muốn. Tùy thuộc vào bạn. –

+1

Nhưng tham chiếu không được người gọi phân bổ. Nó đã được instantiated trong cuộc gọi .. sau đó tôi figured nếu bạn không sử dụng mới sau đó nó sẽ đi ra khỏi phạm vi bởi vì nó sẽ được trên ngăn xếp chứ không phải là đống. –

+4

@BrianCain Ông hoàn toàn cần 'mới', bởi vì nếu không thì đối tượng sẽ bị hủy ngay khi' doSomething() 'kết thúc. –

Trả lời

8

Mặc dù điều này không chính xác nhưng không phải là ý tưởng hay.

MyClass& doSomething() { 
    return *(new MyClass()); 
} 

Sau khi bạn quay lại, không ai có con trỏ ban đầu, vì vậy sẽ không có ai delete nó. * Vì vậy, đó là rò rỉ bộ nhớ.

Bạn nên viết khá nhiều khi không viết new trừ khi bạn có một hàm tạo con trỏ thông minh tương ứng delete tương ứng.


Trong khi đó, dòng này trong mã ban đầu của bạn:

MyClass a = doSomething(); 

... sẽ tạo một bản sao của giá trị anyway. Giả sử đó không phải là lỗi khác mà phải được sửa, tại sao lại bận tâm phân bổ một đối tượng và trả về một tham chiếu đến sao chép và rò rỉ? Chỉ trả lại đối tượng theo giá trị:

MyClass doSomething() { 
    return MyClass(); 
} 

Bây giờ bạn không phải lo lắng về việc xóa bất kỳ thứ gì vì bạn chưa bao giờ tạo bất kỳ thứ gì trên heap.


Thực tiễn tốt nhất thường có thể được tóm tắt trong bốn chữ RAII: Chuyển đổi tài nguyên là khởi tạo. (Và hệ quả, sự hủy diệt đó được giải phóng.) Nếu bạn có thứ gì đó không thể, hoặc đắt tiền, để vượt qua giá trị, thì hãy vượt qua một số xử lý với nó theo giá trị. Ví dụ:

unique_ptr<MyClass> doSomething() { 
    return unique_ptr<MyClass>(new myClass()); 
} 

unique_ptr<MyClass> a = doSomething(); 

Bây giờ nó chỉ là con trỏ được sao chép. Bản thân đối tượng được tạo bên trong doSomething và bị xóa bất cứ khi nào a vượt quá phạm vi (hoặc, nếu bạn chuyển nó sang biến khác, bất cứ khi nào rằng nằm ngoài phạm vi, v.v.).

Mặt khác, nếu MyClass chỉ là một số ít giá trị có thể sao chép dễ dàng **, chỉ cần sao chép nó.


* Không phải không thể để xóa nó; bạn luôn có thể đưa con trỏ đến tham chiếu và delete. Nó chỉ là rất không chắc bạn sẽ bao giờ làm như vậy, và nó sẽ trông lúng túng. Nếu bạn muốn truyền con trỏ xung quanh, hãy chuyển các con trỏ xung quanh. Nếu bạn không muốn bỏ qua các con trỏ xung quanh, hãy quấn quyền sở hữu trong một lớp và chuyển lớp học theo giá trị.

** Bằng "dễ dàng sao chép", tôi có nghĩa là dễ dàng sao chép chúng an toàn và bạn thực sự làm như vậy. Ví dụ, một con trỏ thô hoặc một xử lý tập tin chỉ là một vài byte, và constructor sao chép mặc định sẽ sẵn sàng sao chép chúng cho bạn ... nhưng sau đó bạn kết thúc với nhiều tham chiếu đến cùng một đối tượng heap hoặc tệp, và nó không thể theo dõi người chịu trách nhiệm xóa hoặc đóng nó.

+0

Sau này giả định không có RVO? Hoặc tôi đã bỏ lỡ một cái gì đó ... (Tôi thường xuyên, vì vậy rất ngạc nhiên nếu như vậy). – WhozCraig

+0

@WhozCraig: Có hoặc không có RVO, trình biên dịch không thể tối ưu hóa con trỏ mới được tạo ra, bởi vì bạn đã yêu cầu một cách rõ ràng. Nếu bạn trả về bằng giá trị thay vì tham chiếu, _then_ RVO có thể tối ưu hóa một bản sao và toàn bộ nội dung sẽ cơ bản miễn phí. – abarnert

+0

Tôi sẽ phải tạo lớp bên ngoài hàm để chuyển nó theo giá trị đúng không? Cảm ơn vì thông tin rò rỉ bộ nhớ Tôi nghĩ có điều gì đó kì lạ đang diễn ra nhưng tôi không thể đoán ra nó là gì. Về cơ bản những gì tôi đang tạo ra là một loại phương pháp nhà máy. Vì vậy, trở về một con trỏ nên làm việc sau đó? –

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