打破shared_ptr和unique_ptr之间的循环依赖关系

时间:2016-03-12 10:10:26

标签: c++ shared-ptr smart-pointers unique-ptr circular-dependency

鉴于此代码:

#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是否已足够?

除此之外,鉴于上述设计,我还应该注意其他任何潜在的问题吗?

2 个答案:

答案 0 :(得分:3)

是的,正如您所说的std::weak_ptr

  

此外,std::weak_ptr用于破坏std :: shared_ptr的循环引用。

将成员更改为std::weak_ptr并运行,产生

$ ./a.out 
Disposing Controller
Disposing View

如果您需要,只需致电lock(查看返回值),即可获得std::shared_ptr <\ n> <\ n> <}>

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

可能的警告与std::weak_ptr and multithreading有关。

答案 1 :(得分:2)

使用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表示您的意图成为标准的一部分。