2015-05-21 38 views
3

我知道這聽起來很荒謬,weak_ptrsunique_ptrs,但請忍受我。是否將weak_ptr與unique_ptr配對是一個好主意?

我有一組小部件和動畫對它們起作用。小部件有一個明確的所有者,他們創建並銷燬它們。所有的小部件都是在一個線程中創建,銷燬和動畫的,所以在動畫代碼運行時不能銷燬一個小部件。正如你所看到的,這些小部件是以某種方式與動畫共享的,但是如果小部件被刪除,動畫應該停止。

當前的方法是使用std::unique_ptr作爲窗口小部件的所有者,並將它們暴露爲動畫的原始指針。這使得查找/調試懸掛指針非常困難。一個提議是在所有者類中更改爲std::shared_ptr,並將std::weak_ptrs顯示爲動畫,但這會在系統中添加一些不需要/不需要的開銷。

是否有可能(一個好主意?)在std::unique_ptr的頂部創建某種weak_ptr,只標記指針已被刪除?如果是的話,你可以給我建議一些實現,對於單線程使用來說花費最小。

編輯:

一個更澄清 - 該部件在一個線程中使用,但應用程序有多個線程。同時還有許多動畫並行運行,每個動畫更新60次/秒。來自std::shared_ptr/std::weak_ptr的開銷來自std::shared_ptr內部使用的(原子)計數器,在這種情況下實際並不需要。

編輯:

我不是問我是否可以使用std::weak_ptrstd::unique_ptr,我知道這是不可能的。我問,如果它是一個好主意/可以建立類似的行爲作爲東西是std::weak_ptr可以std::unique_ptr

+0

我想你可以使用一個唯一的指針與一個定製的刪除器,可以跟蹤不太弱的指針。儘管如此,我看不出如何比'shared_ptr'少開銷。我只是使用'shared_ptr',因爲那正是你想要的。 –

+0

但相反,您是通過制定自己獨特的弱ptr解決方案來增加開銷,這是否好? –

+0

'開銷來自(原子)計數器,在這種情況下實際上並不需要。'是的,你需要一些(原子)值來查看指針是否有效,原子布爾(標誌)與原子計數器沒有多大區別。 – KillianDS

回答

2

沒有配對,你不能std::unique_ptr使用std::weak_ptr。就像你說的那樣,你將它製作爲std::shared_ptr並展示std::weak_ptr。就引用計數的開銷而言,我非常懷疑這將是你的應用程序的瓶頸,所以只有當它變成(可能永遠不會)如此時,才能簡介和擔心。

+1

我不建議使用std :: weak_ptr,因爲這不能使用。我建議構建一些行爲類似於std :: weak_ptr的東西,但是在std :: unique_ptr的上下文中 – Felics

+0

@KillianDS我編輯了問題。 – Felics

0

當然,這是一個合理的想法。它提供對物體使用壽命的控制,同時賦予下屬線程檢測其消失的機會。

當然,弱對象的lock()方法需要返回一些本身不允許重新共享的方法。

您可以通過封裝現有的shared_ptr和weak_ptr對象來實現。

一個簡單的例子:

#include <iostream> 
#include <memory> 

// some type we're going to use for testing 
struct Foo { 
    ~Foo() { 
     std::cout << "Foo destroyed" << std::endl; 
    } 

    void use() const { 
     std::cout << "using Foo" << std::endl; 
    } 

}; 

// forward declaration 
template<class T> struct weak_object_ptr; 

// a pointer that keeps the object alive but is not itself copyable 
template<class T> 
struct keep_alive_ptr 
{ 
    // make it moveable 
    keep_alive_ptr(keep_alive_ptr&&) = default; 
    keep_alive_ptr& operator=(keep_alive_ptr&&) = default; 

    // provide accessors 
    T& operator*() const { 
     return *_ptr; 
    } 

    T* operator->() const { 
     return _ptr.get(); 
    } 

private: 
    // private constructor - the only way to make one of these is to lock a weak_object_ptr 
    keep_alive_ptr(std::shared_ptr<T> ptr) 
    : _ptr { std::move(ptr) } 
    {} 

    // non-copyable 
    keep_alive_ptr(const keep_alive_ptr&) = delete; 
    keep_alive_ptr& operator=(const keep_alive_ptr&) = delete; 

    friend weak_object_ptr<T>; 

    std::shared_ptr<T> _ptr; 
}; 

// a weak reference to our shared object with single point of ownership 
template<class T> 
struct weak_object_ptr 
{ 
    weak_object_ptr(std::weak_ptr<T> w) 
    : _weak { std::move(w) } 
    {} 

    keep_alive_ptr<T> lock() const { 
     return keep_alive_ptr<T> { _weak.lock() }; 
    } 
private: 
    std::weak_ptr<T> _weak; 
}; 

// a shared object store and lifetime controller 
template<class T> 
struct object_controller 
{ 

    // helpful universal constructor 
    template<class...Args> 
    object_controller(Args&&...args) 
    : _controller { std::make_shared<T>(std::forward<Args>(args)...) } 
    {} 

    weak_object_ptr<T> get_weak() const { 
     return weak_object_ptr<T> { _controller }; 
    } 

    void reset() { 
     _controller.reset(); 
    } 

private: 
    std::shared_ptr<T> _controller; 
}; 


// test 

using namespace std; 

int main(){ 
    auto foo_controller = object_controller<Foo> {}; 

    auto weak1 = foo_controller.get_weak(); 
    auto weak2 = foo_controller.get_weak(); 

    { 
     auto strong1 = weak1.lock(); 
     strong1->use(); 
     cout << "trying to destroy Foo\n"; 
     foo_controller.reset(); 

     auto strong2 = weak2.lock(); 
     strong2->use(); 
     cout << "strong2 going out of scope\n"; 
    } 

    return 0; 
} 

預期輸出(注意,富的破壞發生早,因爲它是法律允許的):

using Foo 
trying to destroy Foo 
using Foo 
strong2 going out of scope 
Foo destroyed 
相關問題