【问题标题】:No op delete for unique_ptrunique_ptr 没有操作删除
【发布时间】:2015-09-12 10:11:25
【问题描述】:

将 unique_ptr 传递给不执行任何操作的自定义删除器的最简洁方法是什么?我需要一个我正在编写的 JNI 函数,其中 C++ 端需要一个 unique_ptr,但是,我不希望 unique_ptr 持有的对象在退出 JNI 函数时被删除 - 我稍后会处理删除。所以我想做这样的事情:

std::unique_ptr<MyClass, noop_delete> ptr;

在一行中 - 没有单独的函数定义:-)

【问题讨论】:

  • 你基本上传递了一个function pointer,它有一个空的身体。
  • “什么都不做的自定义删除器”:那你为什么需要std::unique_ptr
  • 您说“C++ 端需要一个 unique_ptr”;这在你的控制范围内吗?您能否将 C++ 端更改为 not 期望 unique_ptr
  • 不在我的控制范围内 - 我必须有一个 std::unique_ptr,否则我已经删除了它:-) 我可以做一些事情,比如在 ptr 的定义点声明一个 lambda 类型内联?这就是我要找的。​​span>
  • @Frank 不,你不能因为 lambdas 不能被默认构造。

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


【解决方案1】:

正如@101010 所指出的,std::unique_ptr 带有 nop 删除器是很奇怪的,因为 std::unique_ptr 唯一有价值的东西实际上是删除器。另外,您说“C++ 端需要一个 unique_ptr”,但带有不同删除器的 std::unique_ptr 将是 不同的类型,这可能行不通。

不过,方法如下:

struct nop
{
    template <typename T>
    void operator() (T const &) const noexcept { }
};

template <typename T>
using nop_unique_ptr = std::unique_ptr<T, nop>;

请注意,此 nop 类型可以在任何地方用作无操作来代替单参数函子。

【讨论】:

  • 如果您需要相同的类型,那么您可以使用 std::shared_ptr 而不删除
  • @lisyarus 这很奇怪,我同意,但我实际上有一个用例。对于单元测试,我需要模拟一个保存在唯一 ptr 中的对象。我使用的是 fakeit 框架,它会自动创建仅给定 ABC 接口的模拟对象。一旦 fakeit 创建了一个模拟对象,您就可以获得指向它的指针。问题是 fakeit 管理模拟对象的生命周期。当然,解决方法是一个带有无操作删除器的独特 ptr。
  • @LossMentality 你到底是怎么嘲笑它的?如答案中所述,两个具有不同删除器类型的unique_ptr 本身就是不同的类型。因此,要正确模拟这一点,您必须使您的代码依赖于删除器类型。
  • std::unique_ptr 对它具有唯一性的含义,另外,您不能误删除std::unique_ptr。可能需要这两个属性而不需要删除指向的对象。
  • 这在嵌入式设备中在尝试管理对在整个程序期间保持活动状态的全局内存映射资源的访问时很有用。在这种情况下,带有 noop 删除器的 unique_ptr 具有访问所有权语义,模块能够显式授予和获取对共享资源的访问权。
【解决方案2】:

我对 @lisyarus 在 cmets 中对他的回答提出的问题的回答促使我想出了一个比我在那里给出的更好的解决方案。这涉及@lisyarus 已经陈述的事实:无操作删除器unique_ptr 与带有delete 删除器的unique_ptr 的类型不同。

我将此作为单独的答案发布,因为它可能与其他人相关(此外,这不适合单个评论)。

上下文:对于单元测试,FakeIt 模拟框架管理模拟对象的生命周期,因此当需要模拟通过 unique_ptr 指向的对象时,我们需要一个带有 no-op 删除器的 unique_ptr .

// As in @lisyarus's answer...
struct nop
{
    template <typename T>
    void operator() (T const &) const noexcept { }
};

// NOTE: We have no use for a pointer that doesn't delete unless we're mocking, so 
// the types below are named to indicate that.

#ifndef WE_ARE_BUILDING_UNIT_TESTS
// Production build - we want a unique_ptr that deletes.
template <typename T>
using mockable_unique_ptr = std::unique_ptr<T>;
#else
// Unit test build - we want unique_ptr that doesn't delete.
template <typename T>
using mockable_unique_ptr = std::unique_ptr<T, nop>;
#endif

现在,mockable_unique_ptr 将根据构建类型自动切换类型,这意味着您不必在代码中到处使用#ifdefs。当然,您需要在某些位置#ifdef/#else 并使用稍微不同的代码进行单元测试构建(可能在指针初始化的位置,但如果您的模拟也在那里创建,您需要无论如何都要这样做)。不过,其余代码保持不变,因为 unique_ptr 的界面没有改变。

【讨论】:

    【解决方案3】:

    std::unique_ptr::release 怎么样?如

    void JNIfunc (T*) {};
    std::make_unique( new T) t;
    JNIfunc( t.release);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-23
      • 1970-01-01
      • 1970-01-01
      • 2014-09-21
      相关资源
      最近更新 更多