了解采用自定义删除器的unique_ptr的构造函数

恩里科

我在说什么

我指的是上方的3和4 std::unique_ptr<T,Deleter>::unique_ptr,具有以下签名:

unique_ptr( pointer p, /* see below */ d1 ) noexcept;

我的问题

主要是这些:

  • 的解释/* see below */实际上是什么意思?
  • 作为程序员,在选择将什么作为删除程序类型模板参数传递给我时,如何利用它std::unique_ptr

而且,更详细:

  • 是否以的构造函数std::unique_ptr为模板的事实必须提供deleter模板参数的原因
  • 如果对上述问题的回答是肯定的,那么如果通过类模板自变量从链接页面的含义中选择了这两个构造函数中的任何一个,则该句子格式将不正确
  • 如何能_Dp_Del实际不同,这是怎么重要?

我的尝试未能成功

在这里,我尝试解释我的推理。以上预期的一些问题也分散在文本中。

我的理解是,在C ++ 17之前的版本中,模板类型推导不适用于类,而仅适用于函数,因此在创建模板类的实例(例如)时,模板类的std::unique_ptr所有必需(即,没有= default_type_or_value)模板参数必须通过提供<…>

此外,在中/usr/include/c++/10.2.0/bits/unique_ptr.h,我或多或少地看到了以下内容:

namespace std {
    // …
    template <typename _Tp, typename _Dp = default_delete<_Tp>>
    class unique_ptr {
      public:
        // …
        using deleter_type  = _Dp;
        // …
        template<typename _Del = deleter_type, typename = _Require<is_copy_constructible<_Del>>>
        unique_ptr(pointer __p, const deleter_type& __d) noexcept : _M_t(__p, __d) { }
        // …
    }
    // …
}

构造函数本身是在type参数上进行模板化的_Del,默认为class' deleter_type(这是的别名_Dp);据此我理解,如果我错了,请纠正我(*)std::unique_ptr甚至不能利用C ++ 17的类的模板类型推导,因此_Dp就此重载而言,模板参数仍然是强制性的(即删除对象将作为第二个参数传递给构造函数)。

既然是这种情况,我们传递给的实际类型实std::unique_ptr参可以用引用声明符修饰,如链接页中所述。但这就是我迷路的地方,更不用说我确实看到了这一点,_Dp并且_Del 可能会有所不同(例如,引用声明符可能会有所不同),这使我的理解更加复杂。

但是,我将复制页面的一部分,以解释各种可能的情况:

3-4)构造一个std::unique_ptr拥有以下对象的对象,如下所示p初始化其存储的指针p并初始化一个Deleter D(取决于是否D为引用类型)

  • a)如果D是非引用类型A,则签名为:

    unique_ptr(pointer p, const A& d) noexcept;
    unique_ptr(pointer p, A&& d) noexcept;
    
  • b)如果D是左值引用类型A&,则签名为:

    unique_ptr(pointer p, A& d) noexcept;
    unique_ptr(pointer p, A&& d) = delete;
    
  • c)如果D是左值引用类型const A&,则签名为:

    unique_ptr(pointer p, const A& d) noexcept;
    unique_ptr(pointer p, const A&& d) = delete;
    

在所有情况下,删除器均从初始化std::forward<decltype(d)>(d)如果std::is_constructible<D, decltype(d)>::value为,则这些重载仅参与重载解析true

我可以解释引用文字的唯一方法如下,其中有很多疑问。

  • 如果我们要将删除器d作为参数传递给构造函数,则必须显式将aD作为模板参数传递给...什么?class和/或它的构造函数?甚至可以将模板参数传递给构造函数吗?
  • D可以是以下三种
    1. 如果将其指定为A,则意味着我们希望既可以传递一个(可能是const)左值d也可以传递一个右值作为,因此这两个重载都采用const A&A&&来定义。
    2. 如果我们将其指定为const A&,我们想要一个手段是不能够通过一个右值作为d,因此过载回吐A&&被删除,因为它会绑定到右值,而超载A&是用于instad const A&,因为后者会绑定到右值太。
    3. 如果我们将其指定为const A&,这意味着我们希望能够通过这两个一个左或右值d,所以采取超载const A&是一个挑,而另一个回吐const A&&delete技术了,因为该参数类型无法绑定到左值,并且将治疗右值不不同于const A&确实如答案解释的,最重要的是,它结合到右值防止其他过载,const A&从结合到右值,这将导致在一个悬空参考被存储在std::unique_ptr(为原因这是这里
  • 但是,当右值作为传递时,1.和3.的用例有什么不同d1.将其A&&绑定到const A&并将3.绑定到,因此前者可以窃取资源,而后者则不能。

最后但并非最不重要的一点是,链接页面还添加了特定于C ++ 17的内容:

如果通过类模板参数推导选择了这两个构造函数中的任何一个,则该程序格式不正确。

根据我的理解,这对我一点都不清楚(请参阅上面的(*)):这些构造函数如何进行类型推导?

因此,最重要的问题是:这种方式的复杂性如何std::unique_ptr<T,Deleter>::unique_ptr对我作为程序员有用?

N·希德

的解释/* see below */实际上是什么意思?

它为不同类型指定了构造函数的不同行为D,其中D类的模板参数如中所示std::unique_ptr<T, D>特别是,它考虑以下三种情况:

  • D是“普通”值类型,例如std::unique_ptr<int, Deleter>A只要A可以用于复制/移动构造a Deleter我们就可以将任何类型的任何对象作为该参数传递
  • D是一个非常量引用类型,例如std::unique_ptr<int, Deleter&>:我们可以提供一个非常量左值表达式(并且只能提供一个非常量左值表达式),并提供可用于构造a的任何类型Deleter&(例如,这可能是派生类。)不允许将右值表达式传递给此参数,因为存储对(过期的)临时变量的引用没有意义。
  • D是const引用类型,例如std::unique_ptr<int, const Deleter&>:与上述要点相同,只不过const限定的左值表达式也是合法的。

请注意,在所有这些情况下,唯一的指针的类型纯粹决定D:在AS IN参数,只允许通过的值类型其他D,可用于构建它。

作为程序员,在选择将什么作为删除程序类型模板参数传递给我时,如何利用它std::unique_ptr

通常,您无需担心。std::unique_ptr<T, D>为要使用的删除器类型指定适当的名称:然后,任何A可以适当地用于构造的明智类型D将起作用,而任何不起作用的类型将不起作用。毕竟,这里的详细规范正在增加实现的复杂性,以降低用户的复杂性!

是std :: unique_ptr的构造函数被模板化的事实,为什么必须提供deleter模板参数?

从本质上讲,是的。解决因果关系的方法无关紧要。(可以将其模板化以强制执行“您可能不能将这些构造函数与CTAD一起使用”,或者可能必须对其进行模板化,从而导致“您可能不能将这些构造函数与CTAD一起使用”:最终没有关系。)

如果对上述问题的回答是肯定的,那么如果通过类模板自变量从链接页面的含义中选择了这两个构造函数中的任何一个,则该句子格式将不正确

std::unique_ptr foo(value(), deleter());是非法的,并且应该导致编译错误。这与CTAD的工作方式有关,如果您对此感兴趣,请参阅CTAD上的cppref文档以获得更好的主意。

_Dp和_Del实际上有何区别,这有何重要意义?

我们可以传递一个类型的对象A,其中A是与之不同的类型D,但是可以用该对象构造一个类型的对象D而且,我们要转发这种类型:我们不需要不必要的副本。引用(适当时为lvalue或rvalue)A允许我们直接D在唯一指针中构造a 这类似于.emplace在标准容器中的用法

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

具有自定义删除器的unique_ptr构造函数被删除

初级 5 版。来自自定义删除器函数的 unique_ptr 构造函数

unique_ptr 的有状态自定义删除器

指向重载静态成员的函数指针 - 在 unique_ptr 中用作自定义删除器

如何为包装需要2个参数的ac函数的unique_ptr类成员创建自定义删除器?

将具有自定义删除器的unique_ptr移到shared_ptr

unique_ptr 看不到派生类的自定义构造函数

如何使用删除器调用unique_ptr构造函数?

如何制作unique_ptr和自定义删除器的副本

使用带有unique_ptr的自定义删除器

unique_ptr,自定义删除器和零规则

使用自定义删除器在地图中存储unique_ptr

使用typedef为std :: unique_ptr指定自定义默认删除器

使用std :: function对象将自定义删除器传递给std :: unique_ptr

std :: unique_ptr <T []>和自定义分配器删除器

混淆使用unique_ptr和自定义删除器

未调用std :: unique_ptr中的自定义删除器

std :: unique_ptr使用带有很少参数的自定义删除器

std :: unique_ptr,自定义删除器和类型更改

如何使用lambda和功能作为unique_ptr的自定义删除器

如何在C ++ 11中返回包含自定义删除器的std :: unique_ptr?

无法使用带有std :: move的自定义删除器插入std :: unique_ptr

如何为由 unique_ptr 管理的数组编写自定义删除器?

初始化传递给unique_ptr自定义删除器的函子

如何制作将函数包装在noexcept可检测的可调用对象中的类模板,以用作std :: unique_ptr自定义删除器?

我可以使用自定义删除器简洁地声明std :: unique_ptr吗?

如何将自定义删除器与std :: unique_ptr成员一起使用?

智能指针(unique_ptr)自定义删除器错误C2027和C2338

使用内存池中的自定义删除器将 std::unique_ptr 返回到抽象类型