为什么我应该使用enable_shared_from_this,因为我也可以通过普通赋值获得相同的效果。
struct A : std::enable_shared_from_this<A> {
std::shared_ptr<A> getptr() {
return shared_from_this();
}
};
int main () {
// What is the differentce between this code
std::shared_ptr<A> p1 = make_shared<A>();
std::shared_ptr<A> p2 = p1->getptr();
// Vs this
std::shared_ptr<A> p1 = make_shared<A>();
std::shared_ptr<A> p2 = p1;
}
答案 0 :(得分:4)
因为你不能得到“相同”的效果“,至少不是你想到的那个。
发布的代码方法没有区别,正是因为A
继承自std::enable_shared_from_this<A>
。 p1和p2都是shared_ptr对象,引用相同的具体对象(假设只有一个部分是为你的测试编译的,否则你在重用id名称时会出错)。
std::enable_shared_from_this<T>
允许您从某个对象获取std::shared_ptr<T>
,该对象由某些预先存在的std::shared_ptr<T>
类型T
或其衍生物正式管理,位于您没有{的位置{1}}以另外获得的对象,但由于某种原因需要一个。例如:
std::shared_ptr<T>
在上面的示例中,#include <iostream>
#include <memory>
struct A;
void foo(std::shared_ptr<A> arg)
{
}
struct A : std::enable_shared_from_this<A>
{
void method()
{
foo(shared_from_this());
}
};
int main ()
{
auto a = std::make_shared<A>();
a->method();
}
需要foo
作为参数。从std::shared_ptr<A>
的主体开始,如果没有A::method()
作为基础,则不存在此类机制。如果没有std::enable_shared_from_this<A>
基础,则必须提供另一种机制,将std::enabled_shared_from_this<T>
共享指针传递到调用链,直到达到a
。简而言之,它看起来像这样:
foo
这显然是可怕和可怕的。此外,#include <iostream>
#include <memory>
struct A;
void foo(std::shared_ptr<A> arg)
{
}
struct A
{
void method(std::shared_ptr<A> me)
{
foo(me);
}
};
int main ()
{
std::shared_ptr<A> a = std::make_shared<A>();
a->method(a);
}
无法保证me
实际上是method
std::shared_ptr<T>
。因此,标准委员会用this
祝福我们。
答案 1 :(得分:1)
共享此功能使您可以获得shared_ptr
到shared_ptr
- 托管对象,只要您拥有的是原始指针或引用。
直接从原始指针创建shared_ptr
将创建一个新的,不相关的引用计数器。
答案 2 :(得分:1)
可能值得一提的是shared_from_this
是'。'
最常见的用例是在某些异步进程运行时“让自己保持活力”。一个很好的例子是完成处理程序,另一个是'this'的回调,当它由shared_ptr
控制时。
例如:
#include <memory>
#include <future>
#include <thread>
#include <chrono>
#include <iostream>
using namespace std::literals;
template<class Handler>
void long_process_with_completion_handler(Handler done)
{
std::thread([done] {
std::cout << "long process starts" << std::endl;
std::this_thread::sleep_for(2000ms);
done();
}).detach();
}
struct controller : std::enable_shared_from_this<controller>
{
auto get_lock() const {
return std::unique_lock<std::mutex>(_mutex);
}
void start() {
long_process_with_completion_handler([self = shared_from_this()] {
auto lock = self->get_lock();
std::cout << "all complete" << std::endl;
});
}
mutable std::mutex _mutex;
};
int main()
{
std::condition_variable controller_done;
std::mutex done_mutex;
bool is_controller_done = 0;
// make shared controller
// start its processing
auto pcontroller = std::shared_ptr<controller>{ new controller,
[&](auto*p) {
delete p;
auto lock = std::unique_lock<std::mutex>(done_mutex);
is_controller_done = true;
std::cout << "controller destroyed" << std::endl;
lock.unlock();
controller_done.notify_all();
}};
pcontroller->start();
// destroy the controlling pointer. but our controller is still running...
pcontroller.reset();
auto lock = std::unique_lock<std::mutex>(done_mutex);
controller_done.wait(lock, [&]{ return is_controller_done;});
std::cout << "program ends" << std::endl;
}
答案 3 :(得分:1)
enable_shared_from_this
和shared_from_this
的用例很明确,但我倾向于说在大多数用例中,可以将其删除,转而使用static
方法获取{ {1}}然后从中创建一个新的shared_ptr
(以与OP建议的方法非常相似的方式,但使用静态方法来支持创建新的shared_ptr
)。 / p>
shared_ptr
方法方法的优势是,当没有基础static
时,您不会遇到尝试获取shared_from_this
的错误对于此实例,由shared_ptr
生成。
缺点是API隐式要求调用者带有bad_weak_ptr
,因此如果调用者只有一个指向实例的原始指针,则他无法使用它(调用者可以从原始指针创建shared_ptr
并调用该方法,但是如何判断原始指针是否未被shared_ptr
管理?)。另一方面,如果用户手头有shared_ptr
,他应该确定将其转为unique_ptr
以便调用静态方法应该没问题。
在某种程度上,优点和缺点是同一枚硬币的两面。
在大多数情况下,我更希望API能够与shared_ptr
一起使用(它在某种程度上取决于它),而不是允许使用任何类型的指针,希望有一个管理shared_ptr
为此。这与使用不能以错误方式使用的API的建议相得益彰。
以下是@RichardHodges(很好的例子!)使用静态方法方法而不是shared_ptr
提供的代码:
enable_shared_from_this