2008-09-26 32 views
76

Tôi đang sử dụng rộng rãi boost:shared_ptr trong mã của tôi. Trong thực tế, hầu hết các đối tượng được cấp phát trên heap được giữ bởi shared_ptr. Thật không may điều này có nghĩa là tôi không thể vượt qua this vào bất kỳ chức năng nào có số shared_ptr. Hãy xem xét mã này:Nhận tăng giá :: shared_ptr cho số

void bar(boost::shared_ptr<Foo> pFoo) 
{ 
    ... 
} 

void Foo::someFunction() 
{ 
    bar(this); 
} 

Có hai vấn đề ở đây. Đầu tiên, điều này sẽ không biên dịch vì hàm tạo T * cho shared_ptr là rõ ràng. Thứ hai, nếu tôi buộc nó để xây dựng với bar(boost::shared_ptr<Foo>(this)) Tôi sẽ tạo ra một con trỏ chia sẻ thứ hai cho đối tượng của tôi mà cuối cùng sẽ dẫn đến một đôi-xóa.

Điều này mang lại cho tôi câu hỏi của tôi: Có bất kỳ mẫu chuẩn nào để nhận bản sao con trỏ chia sẻ hiện có mà bạn biết tồn tại từ bên trong phương thức trên một trong các đối tượng đó không? Sử dụng tham chiếu xâm nhập có tính vào tùy chọn duy nhất của tôi ở đây không?

+0

"_Is sử dụng tài liệu tham khảo xâm nhập đếm lựa chọn duy nhất của tôi ở đây _ "Có gì sai với tùy chọn này? – curiousguy

+0

Có thể không có gì. Phụ thuộc vào hoàn cảnh của bạn. Nó làm cho các đối tượng của bạn lớn hơn và có thể không hoạt động ở những nơi mà bạn không có quyền kiểm soát các lớp mà bạn đang giữ các trình thông minh. –

+0

enabe_shared_from_this giờ đây nằm trong 'std ::'. Hãy xem câu trả lời của tôi. –

Trả lời

102

Bạn có thể bắt nguồn từ enable_shared_from_this và sau đó bạn có thể sử dụng "shared_from_this()" thay vì "này" để đẻ trứng một con trỏ chia sẻ để đối tượng tự của riêng bạn.

Ví dụ trong liên kết:

#include <boost/enable_shared_from_this.hpp> 

class Y: public boost::enable_shared_from_this<Y> 
{ 
public: 

    shared_ptr<Y> f() 
    { 
     return shared_from_this(); 
    } 
} 

int main() 
{ 
    shared_ptr<Y> p(new Y); 
    shared_ptr<Y> q = p->f(); 
    assert(p == q); 
    assert(!(p < q || q < p)); // p and q must share ownership 
} 

Đó là một ý tưởng tốt khi đề sinh sản từ một hàm thành viên để thúc đẩy :: liên kết với một shared_from_this() thay vì điều này. Nó sẽ đảm bảo rằng đối tượng không được phát hành.

+0

f() giống như ".Copy()" và nó cũng là một bản sao nông. –

9

Bạn có thực sự tạo nhiều bản sao được chia sẻ của pFoo bên trong thanh không? Nếu bạn không làm bất cứ điều gì điên bên trong, chỉ cần làm điều này:


void bar(Foo &foo) 
{ 
    // ... 
} 
3

Chức năng chấp nhận một con trỏ muốn làm một trong hai hành vi:

  • Sở hữu các đối tượng được thông qua tại, và xóa nó khi nó ra khỏi phạm vi. Trong trường hợp này, bạn chỉ có thể chấp nhận X * và ngay lập tức bọc một scoped_ptr xung quanh đối tượng đó (trong phần thân hàm). Điều này sẽ làm việc để chấp nhận "này" hoặc, nói chung, bất kỳ đối tượng phân bổ heap.
  • Chia sẻ con trỏ (không sở hữu nó) với đối tượng đang được chuyển. Trong trường hợp này, bạn thực hiện không phải muốn sử dụng scoped_ptr vì bạn không muốn xóa đối tượng tại kết thúc chức năng của bạn. Trong trường hợp này, những gì bạn về mặt lý thuyết muốn là một shared_ptr (tôi đã nhìn thấy nó được gọi là linked_ptr ở nơi khác). Thư viện tăng cường có a version of shared_ptr và điều này cũng được đề xuất trong sách C++ hiệu quả của Scott Meyers (mục 18 trong ấn bản thứ 3).

Chỉnh sửa: Rất tiếc, tôi đã đọc sai câu hỏi và bây giờ tôi thấy câu trả lời này không giải quyết chính xác câu hỏi. Dù sao tôi cũng sẽ để nó, trong trường hợp điều này có thể hữu ích cho bất cứ ai làm việc trên mã tương tự.

19

Chỉ cần sử dụng con trỏ thô cho thông số hàm của bạn thay vì shared_ptr. Mục đích của một con trỏ thông minh là kiểm soát tuổi thọ của đối tượng, nhưng tuổi thọ của đối tượng đã được đảm bảo bởi các quy tắc phạm vi C++: nó sẽ tồn tại ít nhất chừng nào kết thúc hàm của bạn.Tức là, mã gọi không thể xóa đối tượng trước khi hàm của bạn trả về; do đó, sự an toàn của một con trỏ "câm" được đảm bảo, miễn là bạn không cố gắng xóa đối tượng bên trong hàm của bạn.

Lần duy nhất bạn cần chuyển một shared_ptr vào một hàm là khi bạn muốn chuyển quyền sở hữu đối tượng cho hàm, hoặc muốn hàm tạo bản sao của con trỏ.

+1

Đồng ý. Nhiều lần bạn có thể sử dụng foo (const Object * object_ptr) {} foo (obj.get()); nơi obj là một tăng :: shared_ptr < Object >. Thực hiện tìm kiếm trên web cho Herb Sutter, là một tác giả khác và bài viết có một số thông tin tuyệt vời về vấn đề này và các vấn đề tương tự. –

+1

Đó là ít bên cạnh điểm, nhưng ... Nếu bạn có thể sử dụng con trỏ, sau đó (rất có thể) bạn có thể sử dụng tài liệu tham khảo, đó là IMO tốt hơn. –

+1

@ denis-bu, ngoại trừ khi một con trỏ 'NULL' là một khả năng. Nhưng bạn làm cho một điểm tốt. –

5

Với C++ 11 shared_ptrenable_shared_from_this hiện nằm trong thư viện chuẩn. Cái sau là, như tên cho thấy, cho trường hợp này chính xác.

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

Ví dụ căn cứ vào đó trong các liên kết ở trên:

struct Good: std::enable_shared_from_this<Good>{ 
    std::shared_ptr<Good> getptr() { 
     return shared_from_this(); 
    } 
}; 

sử dụng:

std::shared_ptr<Good> gp1(new Good); 
std::shared_ptr<Good> gp2 = gp1->getptr(); 
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n'; 
Các vấn đề liên quan