【问题标题】:Can I succintly declare std::unique_ptr with custom deleter?我可以用自定义删除器简洁地声明 std::unique_ptr 吗?
【发布时间】:2021-03-25 04:58:29
【问题描述】:

我正在处理具有关联的 new_free_ 方法的 C 类型。

new_ 的类型签名可能会有所不同,但 free_ 始终是 void free_something(something*);

目前,我以这种方式声明我的unique_ptrs,这似乎过于冗长:

std::unique_ptr<qdr_link_t, decltype(&free_qdr_link_t)> link{new_qdr_link_t(), free_qdr_link_t};

我可以用更少的仪式来做这件事吗?当我的释放器是std::free() 函数时,我看到了一个巧妙的解决方案,位于https://stackoverflow.com/a/43626234/1047788。我试图创建一个可以参数化释放器的版本,但我没有用它。

我能想到的最好的办法是根据上述声明创建一个宏。

【问题讨论】:

  • 我有多种这样的类型,对于每种类型,我都有一个type * new_type(...)void free_type(void)。所以是的。没有多个 new_ 名称相同但签名不同,因为它们都在 C 中声明并且不允许重载。
  • void free_type(void) 怎么知道要释放什么?要释放的东西是否存储在全局中?
  • 傻了,free_函数的签名是void free_type(*type)。很抱歉之前弄错了。

标签: c++ c++11 unique-ptr


【解决方案1】:

我一直在使用以下:

template <auto fptr>
struct Caller {
    template <class... Args>
    auto
    operator()(Args&&... args) noexcept
    {
        return fptr(std::forward<Args...>(args)...);
    }
};

示例用法:

using qdr_freer = Caller<free_qdr_link_t>;

using unique_qdr_ptr = std::unique_ptr<qdr_link_t, qdr_freer>;

[[nodiscard]] unique_qdr_ptr
make_qdr_unique()
{
    return unique_qdr_ptr{new_qdr_link_t()};
}

此实现使用 C++17 功能,因此需要进行一些更改才能在 C++11 中工作。


请注意,虽然Caller 看起来与std::free 很匹配,但严格来说它们并不兼容,因为std::free 是一个标准库函数,并未指定为“可寻址”。

【讨论】:

  • 固定签名template&lt;void(*F)()&gt; 是一种选择;另一个是template&lt;class T, T F&gt;
【解决方案2】:

让语言做艰苦的工作!

#include <memory>

struct qdr_link_t;
qdr_link_t* new_qdr_link_t();
void free_qdr_link_t(qdr_link_t*);

template <typename T, typename Deleter>
auto make_unique_ptr(T* raw, Deleter deleter)
{
    return std::unique_ptr<T, Deleter>(raw, deleter);
}

//std::unique_ptr<qdr_link_t, decltype(&free_qdr_link_t)> link{new_qdr_link_t(), free_qdr_link_t};
auto link = make_unique_ptr(new_qdr_link_t(), free_qdr_link_t);

添加std::forward 品尝(如果你在乎的话)。


对于 C++11,您需要将尾随返回类型 -&gt; std::unique_ptr&lt;T, Deleter&gt; 添加到 make_unique_ptr,或者将其放入“正常”返回类型中。

【讨论】:

  • std::unique_ptr&lt;T, Deleter&gt;的大小而言,这是一个糟糕的软件工程解决方案。每个这样的智能指针都存储一个指向同一个函数的指针,这是不必要的。
  • @MaximEgorushkin 这就是unique_ptr 的工作原理。可以将free_qdr_link_t 包装在一些“硬编码”它的可调用类型中,因此不需要运行时存储。但是这里真的需要这种复杂性吗?最好的软件工程解决方案是最简单的,除非另有要求。
  • 如果有人不厌其烦地使用 C++,这意味着他们想要一个高效而不是简单的解决方案。为了简单的解决方案,他们可以使用 Python。
  • @MaximEgorushkin 为不存储单个函数指针的“效率”编写最复杂的解决方案可能不是编写 C++ 的目的。老实说,“然后使用 Python”是一个愚蠢的建议。如果你坚持这样做,C++ 只会“麻烦”。
  • @user7610 不是真的。至少你必须在某处创建一个新类型来包装free_qdr_link_t,并为你拥有的所有其他释放函数执行此操作。它不能很好地扩展。如果是这样,我会展示的。在我看来,这种方式在简单性、可读性、可维护性、可用性、性能和可扩展性之间取得了适当的平衡。
猜你喜欢
  • 2018-04-13
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 2015-04-09
  • 1970-01-01
  • 2018-01-31
  • 2018-01-02
  • 2017-05-15
相关资源
最近更新 更多