2009-09-10 29 views
26

boost::shared_ptr có một nhà xây dựng bất thườngshared_ptr của boost là gì (shared_ptr <Y> const & r, T * p) được sử dụng cho?

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); 

và tôi là một chút bối rối như những gì này sẽ hữu ích cho. Về cơ bản, nó chia sẻ quyền sở hữu với r, nhưng .get() sẽ trả lại p. không phảir.get()!

Điều này có nghĩa bạn có thể làm một cái gì đó như thế này:

int main() { 
    boost::shared_ptr<int> x(new int); 
    boost::shared_ptr<int> y(x, new int); 

    std::cout << x.get() << std::endl; 
    std::cout << y.get() << std::endl; 

    std::cout << x.use_count() << std::endl; 
    std::cout << y.use_count() << std::endl; 
} 

Và bạn sẽ có được điều này:

0x8c66008 
0x8c66030 
2 
2 

Lưu ý rằng con trỏ là riêng biệt, nhưng cả hai đều khẳng định có một use_count của 2 (kể từ khi họ chia sẻ quyền sở hữu của cùng một đối tượng).

Vì vậy, int thuộc sở hữu của x sẽ tồn tại càng lâu càng xhayy là xung quanh. Và nếu tôi hiểu các tài liệu chính xác, thì int thứ hai sẽ không bao giờ bị hủy. Tôi đã xác nhận điều này với các chương trình thử nghiệm sau đây:

struct T { 
    T() { std::cout << "T()" << std::endl; } 
    ~T() { std::cout << "~T()" << std::endl; } 
}; 

int main() { 
    boost::shared_ptr<T> x(new T); 
    boost::shared_ptr<T> y(x, new T); 

    std::cout << x.get() << std::endl; 
    std::cout << y.get() << std::endl; 

    std::cout << x.use_count() << std::endl; 
    std::cout << y.use_count() << std::endl; 
} 

đầu ra này (như dự kiến):

T() 
T() 
0x96c2008 
0x96c2030 
2 
2 
~T() 

... Vì vậy, tính hữu ích của cấu trúc bất thường này mà chia sẻ quyền sở hữu của một con trỏ là gì , nhưng hành vi giống như một con trỏ khác (mà nó không sở hữu) khi được sử dụng.

+7

Câu hỏi hay. +1 – GManNickG

+3

TL; DR phiên bản: Nó tạo ra một con trỏ đến một đối tượng phụ của 'r'. –

Trả lời

29

Nó rất hữu ích khi bạn muốn chia sẻ một thành viên lớp và một thể hiện của lớp đã được một shared_ptr, như sau:

struct A 
{ 
    int *B; // managed inside A 
}; 

shared_ptr<A> a(new A); 
shared_ptr<int> b(a, a->B); 

họ chia sẻ số lượng sử dụng và các công cụ. Đó là tối ưu hóa cho việc sử dụng bộ nhớ.

+1

câu trả lời hay. rõ ràng, trong ví dụ này, chúng ta sẽ muốn giữ đối tượng 'a' xung quanh miễn là' b' là xung quanh. Tôi nghĩ rằng chúng tôi có một người chiến thắng. –

+0

Không chỉ là một tối ưu hóa cho việc sử dụng bộ nhớ, nhưng trong ví dụ cụ thể, sử dụng một cách tiếp cận khác sẽ kết thúc bằng một cuộc gọi đến 'delete (a-> B)' có thể là bất ngờ (xem xét 'struct A {int b;}; shared_ptr a (new A); shared_ptr b (a, & a-> b) ') –

2

Bạn có thể có con trỏ đến một số trình điều khiển hoặc cấu trúc dữ liệu của cấp thấp hơn có thể phân bổ dữ liệu bổ sung bằng api cấp thấp hơn hoặc các phương tiện khác. Trong trường hợp này, có thể thú vị khi tăng use_count nhưng trả về dữ liệu bổ sung nếu con trỏ đầu tiên sở hữu các con trỏ dữ liệu khác.

8

Mở rộng trên leiz'spiotr's câu trả lời, mô tả này shared_ptr<> 'răng cưa' là từ một bài báo WG21, "Improving shared_ptr for C++0x, Revision 2":

III. Aliasing Hỗ trợ

người dùng nâng cao thường yêu cầu khả năng để tạo ra một shared_ptr dụ p mà chia sẻ quyền sở hữu với khác (master) shared_ptrq nhưng trỏ đến một đối tượng đó không phải là một cơ sở của *q. Ví dụ: *p có thể là thành viên hoặc một thành phần của *q.Phần này đề xuất thêm một hàm xây dựng có thể được sử dụng cho mục đích này.

Một hiệu ứng phụ thú vị của việc tăng cường quyền biểu đạt này là hiện tại các chức năng *_pointer_cast có thể được thực hiện trong mã người dùng. Chức năng nhà máy make_shared được trình bày sau này trong tài liệu này cũng có thể là được triển khai chỉ sử dụng giao diện công khai shared_ptr thông qua hàm tạo răng cưa.

Tác động:

Tính năng này mở rộng giao diện của shared_ptr trong một cách tương thích ngược làm tăng biểu cảm sức mạnh của nó và do đó là mạnh mẽ khuyến khích để được thêm vào C++ 0x tiêu chuẩn . Nó không giới thiệu các vấn đề tương thích nhị phân nguồn và .

văn bản đề xuất:

Thêm vào shared_ptr [util.smartptr.shared] sau constructor:

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); 

Thêm dòng sau vào [util.smartptr. shared.const]:

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p); 

Effects: xây dựng một trường hợp shared_ptr mà các cửa hàng sở hữu pcổ phiếu vớir.

Điều kiện sau:get() == p && use_count() == r.use_count().

Ném: không có gì.

[Lưu ý: Để tránh khả năng của một con trỏ tòn ten, người dùng của constructor này phải đảm bảo rằng p vẫn có giá trị ít nhất cho đến khi nhóm quyền sở hữu của r bị phá hủy. --end note]

[Ghi chú:. constructor này cho phép tạo ra mộtshared_ptr dụ trống với một con trỏ NULL không được lưu trữ. --end lưu ý.]

4

Bạn cũng có thể sử dụng để giữ con trỏ đúc động, ví dụ::

class A {}; 
class B: public A {}; 

shared_ptr<A> a(new B); 
shared_ptr<B> b(a, dynamic_cast<B*>(a.get())); 
+0

một cách sử dụng thú vị khác rõ ràng thuộc vào loại "răng cưa". Điểm tốt. –

0

Đối với "shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));"

tôi nghĩ rằng nó không phải là cách khuyến khích sử dụng con trỏ thông minh.

Cách đề nghị làm chuyển đổi loại hình này nên là:

shared_ptr<B> b(a); 

Vì trong tài liệu Boost nó được đề cập rằng:

shared_ptr<T> có thể ngầm chuyển đổi sang shared_ptr<U> bất cứ khi nào T * thể được chuyển đổi hoàn toàn sang U *. Trong Đặc biệt, shared_ptr<T> là ngầm mui trần để shared_ptr<T> const, để shared_ptr<U> nơi U là một căn cứ truy cập của T, và để shared_ptr<void>.

Bên cạnh đó, chúng tôi cũng có dynamic_pointer_cast mà có thể trực tiếp làm chuyển đổi trên đối tượng thông minh con trỏ và cả hai phương thức này sẽ an toàn hơn nhiều so với tay đúc cách con trỏ thô.

0

Tôi đã đưa constructor răng cưa shared_ptr trong sử dụng trong thư viện nhỏ của tôi:

http://code.google.com/p/infectorpp/ (chỉ IoC container đơn giản của tôi)

Vấn đề là kể từ khi tôi cần một người shared_ptr loại được biết đến để được trả lại từ một lớp đa hình (không biết loại). Tôi không thể chuyển đổi hoàn toàn shared_ptr thành loại tôi cần.

Trong tệp "InfectorHelpers.hpp" (dòng 72-99), bạn có thể thấy rằng đang hoạt động đối với loại IAnyShared.

Trình tạo bí danh tạo shared_ptr không xóa con trỏ mà chúng đang trỏ đến, nhưng chúng vẫn tăng bộ đếm tham chiếu cho đối tượng ban đầu và có thể vô cùng hữu ích.

Về cơ bản, bạn có thể tạo con trỏ tới bất kỳ thứ gì bằng cách sử dụng hàm tạo bí danh và đe dọa nó làm bộ đếm tham chiếu.

//my class 
std::shared_ptr<T> ist; 
int a; //dummy variable. I need its adress 

virtual std::shared_ptr<int> getReferenceCounter(){ 
    return std::shared_ptr<int>(ist,&a); //not intended for dereferencing 
} 

virtual void* getPtr(); //return raw pointer to T 

bây giờ chúng tôi có cả "một bộ đếm tham khảo" và một con trỏ đến một istance của T, đủ dữ liệu để tạo ra một cái gì đó với các nhà xây dựng răng cưa

std::shared_ptr<T> aPtr(any->getReferenceCounter(), //share same ref counter 
       static_cast<T*>(any->getPtr())); //potentially unsafe cast! 

Tôi không giả vờ đã phát minh này sử dụng cho hàm tạo răng cưa, nhưng tôi chưa bao giờ thấy một người nào khác làm như vậy. Nếu bạn đoán nếu mã bẩn đó hoạt động thì câu trả lời là có.

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