我们什么时候应该使用std::enable_shared_from_this
When should we use std::enable_shared_from_this
我只知道std::enable_shared_from_this
形成这个链接。
但是看完下面的代码后,我不知道什么时候使用它。
try {
Good not_so_good;
std::shared_ptr<Good> gp1 = not_so_good.getptr();
} catch(std::bad_weak_ptr& e) {
// undefined behavior (until C++17) and std::bad_weak_ptr thrown (since C++17)
std::cout << e.what() << 'n';
}
上面的代码"不太好",因为在调用getptr()
之前没有现有的shared_ptr
。所以好事应该是:
std::shared_ptr<Good> gp1 = std::make_shared<Good>(); // having a shared_ptr at the beginning
std::shared_ptr<Good> gp2 = gp1->getptr();
但是,如果我已经有一个shared_ptr
对象,为什么不简单地像这样编写代码:std::shared_ptr<Good> gp2 = gp1;
,这意味着我根本不需要std::enable_shared_from_this
。
在我看来,使用std::enable_shared_from_this
是为了确保多个shared_ptr
对象具有相同的控制块,以便我们可以避免双重删除问题。但是,如果我必须在开始时提醒自己创建一个shared_ptr
,为什么不提醒自己使用shared_ptr
对象来创建一个新对象,而不是使用原始指针呢?
关于std::enable_shared_from_this<T>
何时有用的提示在于它的名称:当基于某些请求生成对象时,可能需要返回指向对象本身的指针。如果结果应该是std::shared_ptr<T>
则有必要从通常无法访问std::shared_ptr<T>
的成员函数中返回这样的指针。
从std::enable_shared_from_this<T>
派生提供了一种获取std::shared_ptr<T>
的方法,只需给定一个类型T
的指针。但是,这样做会假设对象已经通过std::shared_ptr<T>
进行管理,如果对象被分配到堆栈上,则会产生混乱:
struct S: std::enable_shared_from_this<S> {
std::shared_ptr<S> get_object() {
return this->shared_from_this();
};
}
int main() {
std::shared_ptr<S> ptr1 = std::make_shared<S>();
std::shared_ptr<S> ptr2 = ptr1->get_object();
// ...
}
在实际方案中,可能存在返回当前对象的std::shared_ptr<T>
的某种条件。
有些用例不能使用模板std::shared_ptr<T>
,例如不透明指针。
在这种情况下,拥有以下内容很有用:
在some_file.cpp
struct A : std::enable_shared_from_this<A> {};
extern "C" void f_c(A*);
extern "C" void f_cpp(A* a) {
std::shared_ptr<A> shared_a = a->shared_from_this();
// work with operation requires shared_ptr
}
int main()
{
std::shared_ptr<A> a = std::make_shared<A>();
f_c(a.get());
}
在some_other.c
struct A;
void f_cpp(struct A* a);
void f_c(struct A* a) {
f_cpp(a);
}
假设我想表示一个计算树。我们将有一个加法表示为从表达式派生的类,其中包含两个指向表达式的指针,因此可以递归计算表达式。但是,我们需要在某个地方结束评估,所以让我们让数字自己评估。
class Number;
class Expression : public std::enable_shared_from_this<Expression>
{
public:
virtual std::shared_ptr<Number> evaluate() = 0;
virtual ~Expression() {}
};
class Number : public Expression
{
int x;
public:
int value() const { return x; }
std::shared_ptr<Number> evaluate() override
{
return std::static_pointer_cast<Number>(shared_from_this());
}
Number(int x) : x(x) {}
};
class Addition : public Expression
{
std::shared_ptr<Expression> left;
std::shared_ptr<Expression> right;
public:
std::shared_ptr<Number> evaluate() override
{
int l = left->evaluate()->value();
int r = right->evaluate()->value();
return std::make_shared<Number>(l + r);
}
Addition(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right) :
left(left),
right(right)
{
}
};
住在科里鲁
请注意,使用return std::shared_ptr<Number>(this);
实现Number::evaluate()
的"明显"方式被破坏了,因为它会导致双重删除。
- 如何将enable-if与模板参数和参数包一起使用
- 如何解决"invalid conversion from 'char' to 'const char*'"
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- std::async from std::async in windows xp
- std::is_reference from std::any
- std::time_point from and to std::string
- "No suitable conversion function from 'std::string' to 'const char *' exists"
- std::chrono::time_point from std::string
- Visual accept std::string from std::byte iterator
- C++中链表的错误"Abort signal from abort(3) (sigabrt) "
- dopen():不以 root 身份运行时"failed to map segment from shared object"
- C++ 中的"template <typename From, typename Tag> struct Alias;"是什么?
- from std::vector to adept::avector
- qt get child (Callout) from QChart
- Webassembly from Javascript
- Generate boost::uuids::uuid from boost::compute::detail::sha
- 什么是"Reading unbounded stream from standard input (Memory Management)"的例子
- Calling C++ dll from python
- 为什么我会收到"invalid conversion from 'Queue*/Stack*' to 'int'"错误消息?
- std::chrono 在从 main 或 from 类方法使用时给出不同的值