Câu hỏi Nhận được một tăng :: shared_ptr cho điều này


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 phân bổ trên heap được tổ chức bởi một 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ần shared_ptr. Hãy xem xét mã này:

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 việc xóa hai lần.

Điều này đưa tôi đến câu hỏi của tôi: Có bất kỳ mẫu chuẩn nào để nhận được một bản sao của con trỏ chia sẻ hiện có mà bạn biết tồn tại từ bên trong một 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?


76
2017-09-26 22:42


gốc


"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?"Có gì sai với tùy chọn này? - curiousguy
Có lẽ 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. - Joe Ludwig
enabe_shared_from_this hiện đang ở std:: . Hãy xem câu trả lời của tôi. - Johan Lundberg


Các câu trả lời:


Bạn có thể lấy được từ enable_shared_from_this và sau đó bạn có thể sử dụng "shared_from_this ()" thay vì "this" để sinh ra một con trỏ được chia sẻ cho đố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 hay khi tạo các luồng từ một hàm thành viên để tăng :: 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.


102
2017-09-26 22:46



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


Chỉ cần sử dụng một con trỏ thô cho tham 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.

Thời gian duy nhất bạn cần truyề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ỏ.


19
2017-09-27 03:59



Đã đồ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 nhà văn 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ự. - bn.
Đó 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. - denis-bu
@ denis-bu, ngoại trừ khi NULL con trỏ là một khả năng. Nhưng bạn làm cho một điểm tốt. - Mark Ransom


boost có giải pháp cho trường hợp sử dụng này, hãy kiểm tra enable_shared_from_this


14
2017-09-26 22:44





Bạn có thực sự tạo ra nhiều bản sao 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)
{
    // ...
}

9
2017-09-26 23:07





Với C ++ 11 shared_ptr và enable_shared_from_this hiện đang ở 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ụ dựa trên điều đó 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';

5
2017-12-25 13:08





Hàm chấp nhận một con trỏ muốn thực hiện một trong hai hành vi:

  • Sở hữu đối tượng được chuyển vào và xóa nó khi nó nằm ngoà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ẻ một con trỏ (không sở hữu nó) cho đối tượng được truyền vào. Trong trường hợp này bạn làm không phải muốn sử dụng một scoped_ptr ở tất cả, vì bạn không muốn xóa đối tượng ở cuối hàm 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 đã phiên bản shared_ptrvà đ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 đã hiểu sai câu hỏi và bây giờ tôi thấy câu trả lời này không chính xác giải quyết 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ự.


3
2017-09-27 00:26