[英]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.