通常我更喜欢返回unique_ptr
来自工厂。
最近遇到了退货的问题unique_ptr
对于继承的类enable_shared_from_this
。此类用户可能会意外地调用shared_from_this()
,尽管它不属于任何人所有shared_ptr
,结果是std::bad_weak_ptr
异常(或 C++17 之前未定义的行为,通常作为异常实现)。
代码的简单版本:
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
但这不是我想要的,因为在很多情况下实际上不需要共享,这会降低效率。
问题是如何实现以下所有目标:
- 允许工厂返回
unique_ptr
- allow
unique_ptr
此类的共享
- allow
shared_ptr
这个类的共享副本(通过shared_from_this()
)
- 避免失败时
unique_ptr
这个类的尝试从这个类中共享(调用get_shared
在上面的例子中)
上述代码满足第 1 至 3 项,问题出在第 4 项上.
成员函数的问题get_shared
问题是它允许双方调用unique_ptr
and shared_ptr
很难区分两者,因此unique_ptr
允许调用此方法并失败。
移动get_shared
是一个静态方法,它获取共享指针,允许区分唯一和共享,从而解决了这个问题:
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));
}
static shared_ptr<Foo> get_shared(unique_ptr<Foo>&& unique_p) {
return shared_ptr<Foo>(std::move(unique_p));
}
static shared_ptr<Foo> get_shared(const shared_ptr<Foo>& shared_p) {
return shared_p->shared_from_this();
}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior - almost as before
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
shared_ptr<Foo> pb3 = Foo::get_shared(pb2);
pb3->doIt();
// ok behavior!
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = Foo::get_shared(std::move(pb4));
pb5->doIt();
}
Code: http://coliru.stacked-crooked.com/a/7fd0d462ed486c44
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)