Nhận được sự thúc đẩy :: shared_ptr cho điều này


76

Tôi đang sử dụng rộng rãi boost:shared_ptrmã của mình. Trên 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 a shared_ptr. Thật không may, điều này có nghĩa là tôi không thể chuyển thisvào bất kỳ hàm nào có a 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_ptrlà rõ ràng. Thứ hai, nếu tôi buộc nó phải xây dựng với bar(boost::shared_ptr<Foo>(this))tôi, tôi sẽ tạo một con trỏ chia sẻ thứ hai đến đối tượng của tôi, điều này cuối cùng sẽ dẫn đến xóa hai lần.

Điều này đưa tôi đến câu hỏi của mình: Có bất kỳ mẫu chuẩn nào để nhận bản sao của con trỏ dùng chung 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 những đối tượng đó không? Sử dụng tham chiếu xâm nhập có tính là lựa chọn duy nhất của tôi ở đây không?


" Sử dụng tham chiếu xâm nhập có đang đếm 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 điểm thông minh.
Joe Ludwig

nitibe_shared_from_this hiện đã có trong std::. Hãy xem câu trả lời của tôi.
Johan Lundberg

Câu trả lời:


102

Bạn có thể lấy từ enable_shared_from_this và sau đó bạn có thể sử dụng "shared_from_this ()" thay vì "this" để tạo ra một con trỏ được chia sẻ tới đối tượng self 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 chuỗi từ một hàm thành viên để boost :: bind với shared_from_this () thay vì cái này. Nó sẽ đảm bảo rằng đối tượng không được giải phóng.


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

19

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 con trỏ thông minh là kiểm soát thời gian tồn tại của đối tượng, nhưng thời gian tồn tại của đối tượng đã được đảm bảo bởi các quy tắc xác định phạm vi C ++: nó sẽ tồn tại ít nhất là khi kết thúc hàm của bạn. Đó 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ố xóa đối tượng bên trong hàm của mình.

Lần duy nhất bạn cần truyền 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 một bản sao của con trỏ.


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

1
Nó hơi nhỏ bên cạnh vấn đề, nhưng ... Nếu bạn có thể sử dụng con trỏ, thì (rất có thể) bạn có thể sử dụng tham chiếu, IMO tốt hơn.
denis-bu

1
@ denis-bu, ngoại trừ khi một NULLcon trỏ là một khả năng. Nhưng bạn làm cho một điểm tốt.
Mark Ransom

Rõ ràng là đã muộn 12 năm, nhưng tôi không hiểu câu trả lời này. Loại đối số cho thanh khác với một con trỏ thô. Nếu không có từ khóa "rõ ràng" sẽ làm cho việc chuyển "this" không biên dịch được, trình biên dịch sẽ không cố gắng tạo shared_ptr từ con trỏ thô, tạo khối đếm tham chiếu trong quá trình này, đặt số tham chiếu thành 1, sau đó tiếp tục thoát khỏi thanh, giảm số lượng tham chiếu xuống 0 và cố gắng xóa "this"?
Foster Boondoggle

1
@FosterBoondoggle đề xuất của tôi là thay đổi loại tham số barthành con trỏ thô.
Mark Ransom


9

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


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

5

Với C ++ 11 shared_ptrenable_shared_from_thishiện đã có trong thư viện chuẩn. Cái thứ hai, như tên cho thấy, chính xác cho trường hợp này.

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';

3

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ó vượt 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 quấn một scoped_ptr xung quanh đối tượng đó (trong thân hàm). Điều này sẽ hoạt động để chấp nhận "cái này" hoặc nói chung, bất kỳ đối tượng được phân bổ theo đống nào.
  • Chia sẻ một con trỏ (không sở hữu nó) cho đối tượng đang được chuyển vào. Trong trường hợp này, bạn không muốn sử dụng scoped_ptr, vì bạn không muốn xóa đối tượng ở cuối hàm của mình. Trong trường hợp này, về mặt lý thuyết những gì bạn muốn là shared_ptr (Tôi đã thấy nó được gọi là linked_ptr ở nơi khác). Thư viện tăng cường có phiên bản shared_ptr , và điều này cũng được đề xuất trong cuốn 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 hơi đọc nhầm 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. Tôi sẽ để nó lại, trong trường hợp điều này có thể hữu ích cho bất kỳ ai làm việc trên mã tương tự.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.