这个shared_ptr片段说了什么?

Cha*_*lie 3 c++ shared-ptr

void del(void(*)()) {}
 
void fun() {}
 
int main()
{
    std::shared_ptr<void()> ee(fun, del);
    (*ee)();
}
Run Code Online (Sandbox Code Playgroud)

这是在cppreference.com上找到的一段代码,我试图理解 shared_ptr 的用途,这是我遇到的一个例子。我尝试运行它并对其进行一些修改,例如在函数体内添加 cout 语句,但我无法理解这里到底发生了什么。

添加更多与我的疑问相关的背景信息,

我的疑惑具体包括:

  1. 这个shared_ptr ee是用一个函数初始化的,那么为什么它不起作用呢std::shared_ptr<void()>ee(fun);
  2. 为什么 ee 的构造函数中有 2 个函数(我假设 shared_ptr 实现是一个类)?
  3. 为什么 del 必须接受函数指针作为其参数?这有什么意义呢?

Ted*_*gmo 7

template <class Y, class Deleter>
std::shared_ptr(Y* ptr, Deleter d);
Run Code Online (Sandbox Code Playgroud)
  1. 这个shared_ptree 是用一个函数初始化的,那么为什么它根本std::shared_ptr<void()>ee(fun);不起作用呢?

要点是创建一个上下文,del无论声明fun的函数中发生了什么,都会在该上下文中调用ee。它可以防止提前退货和例外情况。

  1. 为什么我们的构造函数中有 2 个函数ee(我假设shared_ptr实现是一个类)?

fun是否可以使共享指针认为它拥有资源,以便在超出范围时调用Deleter函数。ee

  1. 为什么del必须接受函数指针作为参数?这有什么意义呢?

这是因为它将使用指向它所拥有的资源的指针来shared_ptr调用Deleter函数。因为它是一个函数指针,所以它实际上不能delete- 但需要它来履行您在创建指向函数的共享指针时制定的合同。

取消引用ee并调用结果是为了清楚起见。它本来也可以fun();,但(*ee)();应该让代码的读者看到调用和函数返回时fun调用的必要性之间的紧密联系。del它不是一个“真正的”上下文处理程序,因为它会出现错误:

template <class Y, class Deleter>
std::shared_ptr(Y* ptr, Deleter d);
Run Code Online (Sandbox Code Playgroud)

不使用 using 的类似构造shared_ptr可能如下所示:

{
    std::shared_ptr<void()> ee(fun, del);
    // here someone mistakenly adds an early return:
    if (argc == 123) return 1;
    (*ee)();  //  or  fun();
} // del may now be called even if `fun` was never called
Run Code Online (Sandbox Code Playgroud)

另一个例子:

void del() {}
void fun() {}

template <class Out>
struct call_context {
    template <class In, class O, class... Args>
    call_context(In&& in, O&& o) : f(std::forward<O>(o)) {
        std::invoke(std::forward<In>(in));
    }
    ~call_context() { f(); }
    Out f;
};
template <class In, class Out>
call_context(In&&, Out&&) -> call_context<Out>;
 
int main()
{
    // call fun and will call del later no matter how `main` is exited:
    call_context cc(fun, del);
}
Run Code Online (Sandbox Code Playgroud)

输出:

#include <iostream>

// same call_context definition as above

void fun() {
    std::cout << "Fun called\n";
}

int main() {
    call_context cc(fun, [] { std::cout << "main exited\n"; });
    std::cout << "---\n";
}
Run Code Online (Sandbox Code Playgroud)