为继承enable_shared_from_this的类获取unique_ptr [英] Getting a unique_ptr for a class that inherits enable_shared_from_this
问题描述
通常,我更喜欢从工厂返回 unique_ptr
。
最近,我遇到了一个问题,即为继承 enable_shared_from_this
的类返回 unique_ptr
。此类的用户可能会意外地调用 shared_from_this()
,尽管该调用不属于任何 shared_ptr
,结果带有 std :: bad_weak_ptr
异常(或直到C ++ 17之前未定义的行为,通常作为异常来实现)。
Usually I prefer returning unique_ptr
from Factories.
Recently I came to the problem of returning a unique_ptr
for a class that inherits enable_shared_from_this
. Users of this class may accidentally cause a call to shared_from_this()
, though it is not owned by any shared_ptr
, which results with a std::bad_weak_ptr
exception (or undefined behavior until C++17, which is usually implemented as an exception).
代码的简单版本:
class Foo: public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
shared_ptr<Foo> get_shared() {return shared_from_this();}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
shared_ptr<Foo> pb3 = pb2->get_shared();
pb3->doIt();
// bad behavior
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = pb4->get_shared(); // exception
pb5->doIt();
}
可能的解决方案是更改工厂方法以返回 shared_ptr
,但这不是我想要的,因为在许多情况下,实际上不需要共享,这会使事情效率降低。
A possible solution is to change the factory method to return shared_ptr
but this is not what I'm looking for, as in many cases there is actually no need for sharing and this will make things less efficient.
问题是如何实现以下所有条件:
The question is how to achieve all of the following:
- 允许工厂返回
unique_ptr
- 允许该类的
unique_ptr
成为共享对象 - allow
shared_ptr
此类的共享副本(通过shared_from_this()
) - 避免当此类的
unique_ptr
试图从此共享时失败(在上面的示例中调用get_shared
)
- allow the factory to return
unique_ptr
- allow
unique_ptr
of this class to become shared - allow
shared_ptr
of this class to get shared copies (viashared_from_this()
) - avoid failure when
unique_ptr
of this class tries to get shared from this (callingget_shared
in above example)
上面的代码满足了项目1至3,问题出在项目4 。
Items 1 to 3 are fulfilled with the code above, the problem is with item 4.
推荐答案
使用多个静态工厂函数和转换函数。为了解决您的意见,我添加了 get_shared
以支持复制共享指针。可以在此处编译: http://ideone.com/UqIi3k
Use multiple static factory functions and conversion functions. To address your comments, I've added get_shared
to support copying a shared pointer. This compiles and is available here: http://ideone.com/UqIi3k
#include <iostream>
#include <memory>
class Foo
{
std::string name;
Foo(const std::string& _name) : name(_name) {}
public:
void doIt() const { std::cout << "Foo::doIt() <" << name << '>' << std::endl;}
virtual ~Foo() { std::cout << "~Foo() <" << name << '>' << std::endl;}
static std::unique_ptr<Foo> create_unique(const std::string & _name) {
return std::unique_ptr<Foo>(new Foo(_name));
}
static std::shared_ptr<Foo> create_shared(const std::string & _name) {
return std::shared_ptr<Foo>(new Foo(_name));
}
static std::shared_ptr<Foo> to_shared(std::unique_ptr<Foo> &&ptr ) {
return std::shared_ptr<Foo>(std::move(ptr));
}
static std::shared_ptr<Foo> get_shared(const std::shared_ptr<Foo> &ptr) {
return std::shared_ptr<Foo>(std::move(ptr));
}
};
int main() {
// ok behavior
auto pb1 = Foo::create_unique("pb1");
pb1->doIt();
std::shared_ptr<Foo> pb2 = Foo::get_shared(std::move(pb1));
//note the change below
std::shared_ptr<Foo> pb3 = Foo::get_shared(pb2);
pb3->doIt();
// also OK behavior
auto pb4 = Foo::create_unique("pb4");
pb4->doIt();
std::shared_ptr<Foo> pb5 = Foo::to_shared(std::move(pb4)); // no exception now
pb5->doIt();
std::shared_ptr<Foo> pb6 = Foo::create_shared("pb6");
pb6->doIt();
std::shared_ptr<Foo> pb7 = std::shared_ptr<Foo>(pb5);
pb7->doIt();
return 0;
}
这篇关于为继承enable_shared_from_this的类获取unique_ptr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!