如何使用静态删除器创建 unique_ptr

How to create unique_ptr with static deleter

我想要一个带有静态删除函数的成员函数 unique-ptr,其中该函数在编译时已知,并且在分配时不需要函数指针。我不知道这是否可能,但 this test 让我感到困惑:

#include <memory>
#include <string>
#include <iostream>

struct Apa {
    std::string name;

    ~Apa() {
        std::cout << name << " deleted\n";
    }
};

static void staticDeleter(Apa *a) {
    std::cout << "static deleter\n";
    delete a;
}

int main() {
    auto deleter = [] (Apa *a) {
        std::cout << "deleter\n";
        delete a;
    };

    {
        // This is what I want but as a member of a struct
        auto ptr1 = std::unique_ptr<Apa, decltype(deleter)>{new Apa{"Apan"}}; // <----------------

        std::cout << sizeof(ptr1) << " -> Apan\n";
    }
    
    {
        auto ptr2 = std::unique_ptr<Apa, decltype(&staticDeleter)>(new Apa{"Beata"}, staticDeleter);
           // When trying to omit this argument this line does not compile ------------^

        std::cout << sizeof(ptr2) << " -> Beta\n";
    }
}

这导致输出

8 -> Apan
deleter
Apan deleted
16 -> Beta
static deleter
Beata deleted

所以除非有一些未知的编译器魔法,指针的大小表明实际上可以创建一个具有静态删除函数的唯一指针。

当试图在结构中做同样的事情时

#include <memory>
#include <iostream>

struct Apa{

};

struct Container {
    using deleter = decltype((Apa*) {}); // Edit: This was a typo: se below

    std::unique_ptr<Apa, deleter> ptr  ;
};

int main() {
    std::cout << sizeof(Container::ptr) << "\n";
}

输出 16 表明 unique_ptr 确实需要指向删除函数的指针。

有什么方法可以使它工作,以便我在静态定义而不是在运行时指定的 class 中定义一个带有自定义删除函数的 unique_ptr?

编辑:

在@eerorika 的一些反馈后,我意识到如果 lambda 编写正确,代码实际上可以工作。 Working code:

#include <memory>
#include <iostream>

struct Apa{
    ~Apa() {
        std::cout << "Apa deleted\n";
    }
};

struct Container {
    using deleter = decltype([](Apa* apa) {
        std::cout << "deleter\n";
        delete apa;
    });

    std::unique_ptr<Apa, deleter> ptr = std::unique_ptr<Apa, deleter>{new Apa} ;
};

int main() {
    std::cout << sizeof(Container::ptr) << "\n";

    Container container{};
}

产量输出:

8
deleter
Apa deleted
using deleter = decltype((Apa*) {});

这是一种不必要的复杂的写作方式:

using deleter = Apa*;

类型 Apa* 不满足 std::unique_ptr 对其删除器施加的要求,因为 Apa* 不是 FunctionObject。示例程序格式错误(至少如果您尝试创建它的实例)。因此,对象的大小并不重要。

Is there any way to make this work so that I define a unique_ptr with a custom deleter function inside a class that is statically defined instead of specified at runtime?

您的 lambda 示例自 C++20 起有效。您可以将类似的删除器定义为 class,它也适用于早期版本。例如:

struct deleter {
    void operator()(Apa* ptr) {
        std::cout << "custom deleter\n";
        delete ptr;
    }
};

struct Container {
    std::unique_ptr<Apa, deleter> ptr  ;
};