【问题标题】:How to create unique_ptr with static deleter如何使用静态删除器创建 unique_ptr
【发布时间】:2021-08-19 08:41:39
【问题描述】:

我想要一个成员函数 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

因此,除非有一些未知的编译器魔法,否则指针的大小表明实际上可以使用静态删除函数创建唯一的 ptr。

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

#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 确实需要指向删除函数的指针。

有什么办法可以让我在静态定义而不是在运行时指定的类中定义一个带有自定义删除器函数的 unique_ptr?

编辑:

经过@eeerorika 的一些反馈后,我意识到如果 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

【问题讨论】:

  • 这是用于 pimpl 模式(指向实现的指针),还是用于在销毁期间挂钩某些附加行为(例如,向侦听器发出销毁通知)、调试助手或其他东西还有吗?
  • 它用于包装一个 c 库,而不必手动指定析构函数。
  • 啊,太好了!很好地使用智能指针来管理外来对象的生命周期。

标签: c++ unique-ptr


【解决方案1】:
using deleter = decltype((Apa*) {});

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

using deleter = Apa*;

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

有什么办法可以让我在静态定义而不是在运行时指定的类中定义一个带有自定义删除器函数的 unique_ptr?

您的 lambda 示例从 C++20 开始工作。您可以将类似的删除器定义为一个类,它也适用于早期版本。例如:

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

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

【讨论】:

  • 现在意识到我的 lambda 语法只适用于 c++20,你的 struct 语法似乎也适用于旧版本
  • @Lasersköld 哦,是的。它依赖于删除器的默认初始化,并且 lambda 在 C++20 之前不能默认初始化。
猜你喜欢
  • 2022-12-31
  • 2013-02-01
  • 2023-03-02
  • 1970-01-01
  • 2015-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多