2012-07-05 13 views
13

Chức năng make_shared() của Boost hứa hẹn sẽ là ngoại lệ an toàn khi cố gắng tạo một shared_ptr.Tại sao tăng không có make_scoped()?

Tại sao không có make_scoped() tương đương? Có cách nào hay nhất?

Dưới đây là một ví dụ mã từ boost::scoped_ptr documentation mà dường như không an toàn với tôi:

boost::scoped_ptr<Shoe> x(new Shoe); 

dòng mã này sẽ thực hiện những ba điều để:

  • Phân bổ bộ nhớ heap cho Shoe
  • Gọi hàm tạo cho Shoe
  • Gọi constructor cho boost::scoped_ptr<Shoe>

Nếu các nhà xây dựng cho Shoe ném một ngoại lệ, bộ nhớ sẽ bị rò rỉ. (xem R. Martinho Fernandes trả lời)scoped_ptr sẽ không xử lý deallocation vì nó chưa được xây dựng.

Đây có phải là sự giám sát không? Hoặc là có một giải pháp mà tôi đã không thông báo?

+0

Ví dụ này an toàn, nhưng không phải là: 'f (boost :: scoped_ptr (giày mới), g());'. Thực hành mã hóa để giải quyết vấn đề: Luôn đặt tên con trỏ thông minh là biến hoặc thành viên, không xây dựng chúng dưới dạng biểu thức con tạm thời. – aschepler

Trả lời

13

Nếu hàm khởi tạo không thành công, không có bộ nhớ bị rò rỉ. Đó là một phần của ngữ nghĩa của new, không có con trỏ thông minh tham gia:

struct Foo { Foo() { throw 23; } }; 
new Foo(); // no memory leaked 

Sự an toàn ngoại lệ bổ sung được cung cấp bởi make_shared đến từ khi bạn khởi tạo hai shared_ptr s trong một biểu thức và hai khởi tạo không được lập trình tự, như trường hợp trong lập luận gọi hàm:

struct Bar { 
    Bar(bool fail) { 
     if(fail) throw 17; 
    } 
} 
f(shared_ptr<Bar>(new Bar(true)), shared_ptr<Bar>(new Bar(false))); 

vì không có trình tự giữa đánh giá của new Bar(true), shared_ptr<Bar>(new Bar(true)), new Bar(false)shared_ptr<Bar>(new Bar(false)), những điều sau có thể xảy ra:

  1. new Bar(false) được đánh giá và thành công: bộ nhớ được cấp phát;
  2. new Bar(true) được đánh giá và không thành công: nó không bị rò rỉ bộ nhớ do đánh giá này;

Không shared_ptr được xây dựng tại thời điểm này và do đó bộ nhớ được cấp trong # 1 hiện bị rò rỉ.

+0

Điều này nghe có vẻ như tôi hiểu bạn? 'new' hứa hẹn bắt các ngoại lệ được ném ra từ hàm tạo, giải phóng bộ nhớ, sau đó ném lại? –

+3

@Drew: Vâng, có điều gì đó có hiệu lực. Nếu bạn quan tâm, điều này được mô tả trong tiêu chuẩn trên §5.3.4 paragrah 18. –

+3

Để hoàn thành một mục đích khác của 'make_shared' (trong hầu hết các triển khai) là nó phân bổ bộ nhớ cho số tham chiếu tại cùng thời điểm với đối tượng được tạo (phân bổ một khối đủ lớn cho đối tượng và số đếm) để bạn không phải chịu hình phạt hiệu suất nếu hai phân bổ heap. 'Scoped_ptr' (hoặc' unique_ptr' trong C++ 11 không cần số tham chiếu và do đó không thu được bất kỳ thứ gì từ nó trong bộ phận đó. – John5342

1

Nếu giày ném thì giày không được xây dựng nên không có gì scoped_ptr thực sự có thể làm. Không? Scoped_ptr x nằm trên ngăn xếp và sẽ được dọn sạch khi thoát khỏi phạm vi.

14

scoped_ptr đặt trước ngữ nghĩa di chuyển và không thể đọc được theo thiết kế. Do đó, make_scoped sẽ không thể thực hiện được vì để trả về một đối tượng từ một hàm, loại của nó phải được di chuyển hoặc có thể sao chép được.