将从工厂方法创建的 unique_ptr 转换为 shared_ptr 并使用 shared_from_this 后遇到 std::bad_weak_ptr 异常
总之,我有一个从 std::enabled_shared_from_this
继承的类,并且有一个工厂方法返回它的 std::unique_ptr
。在另一个类中,我将前一个类对象的 std::unique_ptr
转换为 std::shared_ptr
,然后调用 shared_from_this()
,然后抛出 std::bad_weak_ptr
。代码如下所示:
#include <memory>
#include <iostream>
struct Executor;
struct Executor1 {
Executor1(const std::shared_ptr<Executor>& executor,
int x): parent(executor) {
std::cout << x << std::endl;
}
std::shared_ptr<Executor> parent;
};
struct Backend {
virtual ~Backend() {}
virtual void run() = 0;
};
struct Executor: public Backend, public std::enable_shared_from_this<Executor> {
const int data = 10;
virtual void run() override {
Executor1 x(shared_from_this(), data);
}
};
// std::shared_ptr<Backend> createBackend() {
std::unique_ptr<Backend> createBackend() {
return std::make_unique<Executor>();
}
class MainInstance {
private:
std::shared_ptr<Backend> backend;
public:
MainInstance(): backend(createBackend()) {
backend->run();
}
};
int main() {
MainInstance m;
return 0;
}
确实改变了 std::unique_ptr
到 std::shared_ptr
可以解决问题,但据我了解,一般来说,工厂模式应该更喜欢返回一个unique_ptr。考虑到软件工程的良好实践,是否有更好的解决方案?
In summary, I have a class inherited from std::enabled_shared_from_this
, and there is a factory method return an std::unique_ptr
of it. In another class, I convert the std::unique_ptr
of the previous class object to std::shared_ptr
, and then I call shared_from_this()
, which then throws std::bad_weak_ptr
. The code is shown below:
#include <memory>
#include <iostream>
struct Executor;
struct Executor1 {
Executor1(const std::shared_ptr<Executor>& executor,
int x): parent(executor) {
std::cout << x << std::endl;
}
std::shared_ptr<Executor> parent;
};
struct Backend {
virtual ~Backend() {}
virtual void run() = 0;
};
struct Executor: public Backend, public std::enable_shared_from_this<Executor> {
const int data = 10;
virtual void run() override {
Executor1 x(shared_from_this(), data);
}
};
// std::shared_ptr<Backend> createBackend() {
std::unique_ptr<Backend> createBackend() {
return std::make_unique<Executor>();
}
class MainInstance {
private:
std::shared_ptr<Backend> backend;
public:
MainInstance(): backend(createBackend()) {
backend->run();
}
};
int main() {
MainInstance m;
return 0;
}
Indeed changing std::unique_ptr<Backend> createBackend()
to std::shared_ptr<Backend> createBackend()
can solve the problem, but as I understand, in general, the factory pattern should prefer return a unique_ptr. Considering a good pratice of software engineering, is there a better solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的示例执行
std::shared_ptr(uptr)
其中uptr
是std::unique_ptr
,相当于std::shared_ptr(p, d)
,其中p
是类型后端*
。此构造函数使用p
启用shared_from_this
- 但这是无操作的,因为Backend
没有明确且可访问的基类,该基类是enable_shared_from_this
的专门化为了使
Executor::enable_from_this
工作,您需要传递给shared_ptr
构造函数 静态类型为 Executor*(或从中派生的某种类型)的指针。Your example executes
std::shared_ptr<Backend>(uptr)
whereuptr
isstd::unique_ptr<Backend>
, which is equivalent tostd::shared_ptr<Backend>(p, d)
wherep
is of typeBackend*
. This constructor enablesshared_from_this
withp
- but that's a no-op, asBackend
doesn't have an unambiguous and accessible base class that is a specialization ofenable_shared_from_this
In order for
Executor::enable_from_this
to work, you need to pass to ashared_ptr
constructor a pointer whose static type isExecutor*
(or some type derived therefrom).好吧,我找到了一个简单的解决方案,即使用
auto
作为工厂函数的返回类型,而不是std::unique_ptr
或std::shared_ptr
,并将std::make_unique
保留在工厂函数内。工厂函数createBackend
应该是:在这种情况下,可以自动确定返回类型,尽管我不知道它到底是如何工作的。此代码可以返回
unique_ptr
或shared_ptr
,这应该比仅使用shared_ptr
更好。我测试了 clang 和 gcc,它们都有效,但我仍然不确定类型推导和隐式转换是否能保证这一点。更新:
实际上,我发现
auto
将上面的返回类型推导为std::unique_ptr
而不是std::unique_ptr
,这可能是代码有效的原因。但使用 auto 有一个问题:如果您在 if-else 块中返回智能指针,其中返回类型根据某些参数而变化,则 auto 无法确定类型。例如:这里,
Executor
和Intepreter
都派生自Backend
。我认为正确的解决方案包括:Backend
而不是从std::enable_shared_from_this
继承它的派生类;shared_from_this
之后使用dynamic_pointer_cast
将shared_ptr
转换为派生类。完整代码列于:
https://gist.github.com/HanatoK/8d91a8ed71271e526d9becac0b20f758
Ok, I find a simple solution, that is, using
auto
as the return type of the factory function, instead ofstd::unique_ptr
orstd::shared_ptr
, and keepingstd::make_unique
inside the factory function. The factory functioncreateBackend
should be:In this case, the return type can be automatically determined, although I don't know how it works exactly. This code can return either
unique_ptr
orshared_ptr
, which should be better than just usingshared_ptr
. I tested clang and gcc, and both of them worked, but I am still not sure if this is gauranteed by the type deduction and the implicit conversion.Update:
Actually, I have found that
auto
deduces the return type above asstd::unique_ptr<Executor>
instead ofstd::unique_ptr<Backend>
, which might be the reason why the code works. But usingauto
has an issue: if you return the smart pointer in an if-else block, where the return type varies depending on some parameters, then auto cannot determine the type. For example:Here, both
Executor
andIntepreter
derive fromBackend
. I think a correct solution includes:Backend
instead of its derived classes fromstd::enable_shared_from_this
;dynamic_pointer_cast<Derived class>
to cast theshared_ptr
to derived class aftershared_from_this
.The full code is listed in:
https://gist.github.com/HanatoK/8d91a8ed71271e526d9becac0b20f758