简体   繁体   English

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

[英]Breaking a circular dependency between a shared_ptr and a unique_ptr

Given this code: 给出以下代码:

#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;
}

I think that the controller object will never be disposed (confirmed by running it ). 我认为controller对象将永远不会被处置(通过运行确认)。

In order to alleviate this issue, is it sufficient to make the observer variable a weak_ptr instead of a shared_ptr ? 为了缓解此问题,将observer变量设为weak_ptr而不是shared_ptr是否足够?

Besides this, is there any other potential issue that I should be aware of, given the above design? 除此之外,鉴于上述设计,我还有其他潜在的问题要注意吗?

Yes, as you state about std::weak_ptr : 是的,当您声明std::weak_ptr

In addition, std::weak_ptr is used to break circular references of std::shared_ptr. 另外, std::weak_ptr用于中断std :: shared_ptr的循环引用。

Changing the member to std::weak_ptr and running, yields 将成员更改为std::weak_ptr并运行,将产生

$ ./a.out 
Disposing Controller
Disposing View

When you need it, just call lock (checking the return value), to obtain a std::shared_ptr (which you should not store as a member): 在需要时,只需调用lock (检查返回值),以获得std::shared_ptr (不应将其存储为成员):

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

A possible caveat has to do with std::weak_ptr and multithreading . 可能的警告与std::weak_ptr和multithreading有关

Using a std::weak_ptr would be okay, but given that the lifetime of the View is tied to its Controller , you can just store a regular pointer to the Controller . 使用std::weak_ptr可以,但是鉴于View的生命周期与其Controller ,您只需存储指向Controller的常规指针即可。 This way, the Controller doesn't have to be stored in a std::shared_ptr , and you can get rid of the std::enable_shared_from_this two-stage initialization mess. 这样, Controller就不必存储在std::shared_ptr ,并且您可以摆脱std::enable_shared_from_this两个阶段的初始化过程。

I would also make SetObserver private and make Controller a friend of View for safety reasons. 出于安全考虑,我还将SetObserver私有,并让Controller成为View的朋友。 They're already tightly coupled after all. 毕竟他们已经紧密地联系在一起了。

#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>());
}

As a side note, you could use std::observer_ptr to signal your intent when it becomes part of the standard. 作为附带说明,您可以使用std::observer_ptr表示您的意图,使其成为标准的一部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM