通常,我更喜欢从工厂返回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
unique_ptr
成为共享的shared_ptr
获取共享拷贝(通过shared_from_this()
)unique_ptr
尝试与之共享时失败(在上面的示例中调用get_shared
)上面的代码完成了项目1至3,问题在于项目4 。
最佳答案
使用多个静态工厂函数和转换函数。为了解决您的意见,我添加了get_shared
以支持复制共享指针。可以在此处编译: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;
}