2012-08-26 15 views
5

Trước hết, tôi nhận ra điều này hoàn toàn mâu thuẫn với mục đích của shared_ptr. Tôi đang đối phó với một số mã thư viện nơi các thể hiện của một ParticleSystem mong muốn có một shared_ptr được truyền cho chúng trong khi xây dựng để thiết lập kết cấu được sử dụng cho mỗi hạt. Vấn đề là, tôi đã xây dựng phần còn lại của chương trình theo cách mà kết cấu của tôi có quyền sở hữu cụ thể (nếu đó là thuật ngữ đúng) - TextureCache sở hữu tất cả Textures. Vì vậy, tôi cần một cách để làm việc với lớp ParticleSystem này mà không cho phép nó xóa kết cấu của tôi. Nếu tôi chỉ đơn giản là tạo một thể hiện mới như ParticleSystem(std::shared_ptr<Texture>&myTexture) thì nó sẽ cố gắng phá hủy kết cấu khi nó bị phá hủy (đó là một hoạt động không mong muốn và không hợp lệ, vì kết cấu của tôi thậm chí không được tạo ra với new).Chuyển một đối tượng đến một hàm mong muốn shared_ptr mà không thực sự chia sẻ quyền sở hữu

Cách sạch nhất mà tôi nhìn thấy xung quanh vấn đề này là một cái gì đó như thế này:

  1. Tạo một shared_ptr giữ kết cấu trong chức năng mà tạo ra ParticleSystem.
  2. Sau đó sử dụng vị trí mới, xây dựng lại shared_ptr trong cùng một vị trí bộ nhớ như shared_ptr mà tôi vừa tạo. Kết cấu bây giờ sẽ có số tham chiếu là 2.
  3. Tạo hệ thống hạt.
  4. Hãy để shared_ptr nằm ngoài phạm vi. Deconstructor của nó sẽ được gọi kể từ khi nó được cấp phát trên stack, và nó sẽ giảm số lượng tham chiếu chỉ bằng 1. Do đó, số tham chiếu cho đối tượng sẽ luôn lớn hơn 1 lần so với thực tế, và vì vậy nó sẽ không bao giờ bị hủy tự động.

Tôi tin rằng giải pháp này là âm thanh, nhưng nó vẫn cảm thấy vô cùng đáng sợ. Có cách nào tốt hơn để giải quyết vấn đề của tôi không?

+0

Tại sao không có trong bộ nhớ cache shared_ptrs kết cấu của bạn? –

+0

@Vaughn là khả thi, nhưng nó có vẻ như một mức độ không cần thiết của indirection bằng cách theo dõi con trỏ đến kết cấu hơn là kết cấu và nó sẽ là lạm dụng các con trỏ chia sẻ ngữ nghĩa vì bộ nhớ cache kết cấu vẫn chịu trách nhiệm quyết định khi nào để giải phóng kết cấu - nó sẽ không được * chia sẻ * quyền sở hữu. – Ponkadoodle

Trả lời

4

Nếu bạn muốn chuyển con trỏ không được quản lý (mà bạn tự quản lý) để mã con trỏ thông minh mong đợi như shared_ptr, bạn có thể chỉ vô hiệu hóa chức năng con trỏ «thông minh» bằng cách tạo ra sản phẩm nào, nhưng không phải null shared_ptr qua aliasing constructor:

Texture* unmanagedPointer = ... 
shared_ptr<Texture> smartPointer(shared_ptr<Texture>(), unmanagedPointer); 

giải pháp này là hiệu quả hơn và ngắn hơn so với tùy chỉnh deleter người khác đề nghị, vì không có phân bổ khối điều khiển và tính tham khảo sẽ trên.

Một số chi tiết bổ sung có thể được tìm thấy ở đây:

What is the difference between an empty and a null std::shared_ptr in C++?

How to avoid big memory allocation with std::make_shared

0

Lưu trữ shared_ptr trong bộ nhớ cache của bạn như Vaughn Cato đề xuất. Để loại bỏ một kết cấu từ bộ nhớ cache khi không có ai sử dụng nó chỉ cần kiểm tra nếu use_count chức năng của shared_ptr lợi nhuận 1, có nghĩa là bộ nhớ cache là chủ sở hữu duy

3

Bạn có thể tạo shared_ptr với custom deleter that does nothing. Điều này sẽ ngăn chặn việc xóa các họa tiết thuộc sở hữu của shared_ptr này.

struct null_deleter 
{ 
    void operator()(void const *) const 
    { 
    } 
}; 

shared_ptr<Texture> CreateTexture(Texture* myTexture) 
{ 
    shared_ptr<Texture> pTexture(myTexture, null_deleter()); 
    return pTexture; 
} 
+0

+1 cho lạm dụng quảng cáo của deleter. –

1

shared_ptr cho phép bạn cung cấp bộ lọc tùy chỉnh. Vì vậy, shared_ptr có thể được sử dụng cho bộ nhớ allocaed với malloc hoặc bất kỳ kế hoạch phân bổ bộ nhớ bạn đang sử dụng, bạn thậm chí có thể sử dụng nó để tự động mở khóa một mutex hoặc đóng một tập tin, nhưng tôi digress. Bạn có thể tạo ra một shared_ptr với một dấu phân cách null mà sẽ không làm bất cứ điều gì khi số lượng referene của nó đạt đến 0.