1

鑑於這種碼之間的循環依賴關係:打破一個shared_ptr和的unique_ptr

#include <iostream> 
#include <memory> 

class Controller; 

class View { 
public: 
    ~View() { 
     std::cout << "Disposing View" << std::endl; 
    } 

    void SetObserver(std::shared_ptr<Controller> a_observer) { 
     observer = a_observer; 
    } 
private: 
    std::shared_ptr<Controller> observer; 
}; 

class Controller : public std::enable_shared_from_this<Controller> { 
public: 
    static std::shared_ptr<Controller> Create(std::unique_ptr<View> view) { 
     //Can't use std::make_shared due to visibility rules :(
     auto controller = std::shared_ptr<Controller>(new Controller(std::move(view))); 

     controller->Init(); 

     return controller; 
    } 

    ~Controller() { 
     std::cout << "Disposing Controller" << std::endl; 
    } 
private: 
    std::unique_ptr<View> view; 

    explicit Controller(std::unique_ptr<View> a_view) : view(std::move(a_view)) {} 

    Controller(const Controller&) = delete; 

    void Init() { 
     view->SetObserver(shared_from_this()); 
    } 
}; 

int main() { 
    auto view = std::make_unique<View>(); 

    auto controller = Controller::Create(std::move(view)); 

    return 0; 
} 

我認爲controller對象將永遠不會被設置(由running it證實)。

爲了減輕這個問題,是否足以使observer變量變爲weak_ptr而不是shared_ptr

除此之外,鑑於上述設計,是否還有其他潛在問題需要我注意?

+0

*「由於可見性規則,不能使用std :: make_shared」* - 請參閱http://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class -with-only-protected-or-private-const –

+0

@ChristianHackl感謝您將這個答案鏈接起來,但我想我現在堅持使用'new'。我不想在代碼中添加太多混亂。 –

回答

2

是的,當你說出約std::weak_ptr

此外,std::weak_ptr是用來打破的std :: shared_ptr的循環引用。

更改成員std::weak_ptr並運行,產量

$ ./a.out 
Disposing Controller 
Disposing View 

當你需要它,只需調用lock(檢查返回值),以獲得std::shared_ptr(你應該店作爲成員):

void doSomethingWithView() { 
    auto obs = observer.lock();                                           
    if(obs) { 
     // Still valid 
    } 
} 

甲可能的警告與std::weak_ptr and multithreading有關。

+0

感謝與多線程相關的單挑! –

1

使用std::weak_ptr會沒問題,但考慮到View的使用期限與其Controller相關聯,您可以將常規指針存儲到Controller。這樣,Controller不必存儲在std::shared_ptr中,您可以擺脫std::enable_shared_from_this兩階段初始化混亂。

我也會讓SetObserver私密,並且爲了安全起見讓Controller成爲View的朋友。畢竟他們已經緊密結合在一起了。

#include <memory> 

class Controller; 

class View { 
    friend class Controller; 

private: 
    void SetObserver(Controller* a_observer) { 
     observer = a_observer; 
    } 

private: 
    Controller* observer = nullptr; 
}; 

class Controller { 
public: 
    explicit Controller(std::unique_ptr<View> a_view) : 
     view(std::move(a_view)) { 
     view->SetObserver(this); 
    } 

private: 
    std::unique_ptr<View> view; 
}; 

int main() { 
    Controller controller(std::make_unique<View>()); 
} 

作爲一個側面說明,你可以使用std::observer_ptr當它成爲標準的一部分,以顯示你的意圖。

+0

我不知道'std :: observer_ptr'。看起來像一個整潔的未來實現。謝謝! –

相關問題