打破 shared_ptr 和 unique_ptr 之间的循环依赖
Breaking a circular dependency between a shared_ptr and a 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
就足够了吗?
除此之外,考虑到上述设计,还有其他我应该注意的潜在问题吗?
是的,正如您所说 std::weak_ptr
:
In addition, std::weak_ptr
is used to break circular references of std::shared_ptr.
将成员更改为 std::weak_ptr
和 运行,得到
$ ./a.out
Disposing Controller
Disposing View
当你需要它的时候,只要调用lock
(检查return值),得到一个std::shared_ptr
(你应该而不是 会员店):
void doSomethingWithView() {
auto obs = observer.lock();
if(obs) {
// Still valid
}
}
一个可能的警告与 std::weak_ptr
and multithreading 有关。
使用 std::weak_ptr
没问题,但考虑到 View
的生命周期与其 Controller
相关联,您可以只存储指向 [=13] 的常规指针=].这样,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
来表明您的意图。
鉴于此代码:
#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
就足够了吗?
除此之外,考虑到上述设计,还有其他我应该注意的潜在问题吗?
是的,正如您所说 std::weak_ptr
:
In addition,
std::weak_ptr
is used to break circular references of std::shared_ptr.
将成员更改为 std::weak_ptr
和 运行,得到
$ ./a.out
Disposing Controller
Disposing View
当你需要它的时候,只要调用lock
(检查return值),得到一个std::shared_ptr
(你应该而不是 会员店):
void doSomethingWithView() {
auto obs = observer.lock();
if(obs) {
// Still valid
}
}
一个可能的警告与 std::weak_ptr
and multithreading 有关。
使用 std::weak_ptr
没问题,但考虑到 View
的生命周期与其 Controller
相关联,您可以只存储指向 [=13] 的常规指针=].这样,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
来表明您的意图。