【问题标题】:Confused using unique_ptr and a custom deleter使用 unique_ptr 和自定义删除器感到困惑
【发布时间】:2015-02-19 14:54:52
【问题描述】:

我正在尝试将unique_ptrSDL_Surface 类型的自定义删除器一起使用。这只是一个使用int 类型的示例,但我希望你能明白。

#include <iostream>
#include <functional>
#include <memory>

typedef int SDL_Surface;


SDL_Surface * CreateSurface()
{
    SDL_Surface * p = new SDL_Surface;
    return p;
}

void FreeSurface(SDL_Surface *p)
{
    delete p;
}

int main() {
    std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > > uptr_1; 

    //how to assign a value to uptr_1 and the deleter? 

    return 0;
}

uptr_1 是否正确声明并初始化为nullptr?如果是这样,我该如何分配指针和删除函数?

我该如何封装这个: std::unique_ptr&lt; SDL_Surface, std::function&lt; void (SDL_Surface *) &gt; &gt; 与删除器不总是在我想要的每个 SDL_Surface 上写下该行,另一个 typedef?

我刚刚开始学习 C++11 功能,这对我来说很难。

【问题讨论】:

  • std::unique_ptr&lt;SDL_Surface, std::function&lt; void (SDL_Surface *) &gt; &gt; uptr_1(CreateSurface(), &amp;::FreeSurface);
  • std::function 在一般情况下对于删除器来说是一个糟糕的选择,因为它的构造函数可以抛出,但unique_ptr 的删除器的构造函数不能抛出。但是,如果您只将它与普通函数指针一起使用,它是安全的。

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


【解决方案1】:

您可以使用指针和删除器初始化unique_ptr,如果稍后重新分配,则可以正常使用=

std::unique_ptr<SDL_Surface, std::function<void (SDL_Surface *)>> uptr_1(CreateSurface(), &FreeSurface);

uptr_1 = std::unique_ptr<SDL_Surface, std::function<void (SDL_Surface *)>>(CreateSurface(), &FreeSurface);

详情请参阅suitable docs

要缩短长类型,您确实可以使用类型别名(typedefusing):

typedef std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)> Surface_ptr;

//or

using Surface_ptr = std::unique_ptr<SDL_Surface, void (*)(SDL_Surface*)>;

请注意,我实际上使用void (*)(SDL_Surface*) 作为删除器类型。如果您知道您总是会传入一个实际函数(或无状态 lambda),则没有理由拖入 std::function,因为类型擦除会产生一些开销。

此外,您还可以通过为删除器创建一个可默认构造的仿函数来进一步缩短它:

struct FreeSurface_Functor
{
  void operator() (SDL_Surface *s) const
  {
    FreeSurface(s);
  }
};

这样,您可以将指针的类型设为std::unique_ptr&lt;SDL_Surface, FreeSurface_Functor&gt;(可能是别名),而不必提供删除器;它将是默认构造的:

std::unique_ptr<SDL_Surface, FreeSurface_Functor> uptr_1(CreateSurface());

【讨论】:

  • 如果指针为 nullptr,我是否需要检查自定义删除器?或者如果指针为 nullptr,std::unique_ptr 不会调用默认删除器?感谢您的回答。
  • @FrameBuffer 你不必检查。 unique_ptr 保证为您进行检查,并且仅在非空时调用删除器。你可以在the docs I've linked找到类似的东西。
  • 您可能会指出,定义无状态删除器类类型的技术是首选,因为高质量的unique_ptr 实现将使用空基优化来优化它们的存储。
【解决方案2】:

我会选择decltype

std::unique_ptr<SDL_Surface, decltype(&FreeSurface)> uptr_1(
          CreateSurface(),
          FreeSurface
);

【讨论】:

    【解决方案3】:

    uptr_1 是否正确声明并初始化为 nullptr

    是的,默认构造的 unique_ptr 将引用 null。

    如果是这样,如何分配指针和删除函数?

    你应该用参数构造unique_ptr

     std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > > uptr_1{CreateSurface(), FreeSurface};
    

    或者,在默认构造之后,您可以使用临时的移动分配

    uptr_1 = std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *) > >{CreateSurface(), FreeSurface};
    

    正如您自己建议的那样,类型别名会有所帮助

    using SDL_Uptr = std::unique_ptr<SDL_Surface, std::function< void (SDL_Surface *)>>;
    SDL_Uptr  uptr_1;
    uptr_1 = SDL_Uptr{CreateSurface(), FreeSurface};
    

    如果它变得重复,中间函数可以帮助简化它(如果你做了很多,它可能会这样做)。

    std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)>
    make_sdl_ptr() {
        return std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)>{CreateSurface(), FreeSurface};
    }
    

    然后您可以使用auto uptr = make_sdl_ptr(); 调用它

    Angew 使用 DefaultConstructible 删除器调用您的函数的回答也是一个非常好的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 2012-03-01
      • 2013-03-30
      • 1970-01-01
      相关资源
      最近更新 更多