C++ 了解独特的ptr和x27;s构造函数,该构造函数接受自定义删除程序 我在说什么

C++ 了解独特的ptr和x27;s构造函数,该构造函数接受自定义删除程序 我在说什么,c++,templates,c++17,unique-ptr,type-deduction,C++,Templates,C++17,Unique Ptr,Type Deduction,我所指的覆盖图是3和4,具有以下签名: unique_ptr(指针p,/*见下文*/d1)无异常; 我的问题 主要包括: /*见下文*/的解释实际上是什么意思 作为一名程序员,在选择将什么作为deleter类型模板参数传递给std::unique_ptr时,如何利用它 但更详细地说: std::unique_ptr的构造函数是模板化的,这是必须提供deleter模板参数的原因吗 如果前面问题的答案是肯定的,那么如果通过从链接页面中的类模板参数推断选择了这两个构造函数中的任何一个,那么程序

我所指的覆盖图是3和4,具有以下签名:

unique_ptr(指针p,/*见下文*/d1)无异常;
我的问题 主要包括:

  • /*见下文*/
    的解释实际上是什么意思
  • 作为一名程序员,在选择将什么作为deleter类型模板参数传递给
    std::unique_ptr
    时,如何利用它
但更详细地说:

  • std::unique_ptr
    的构造函数是模板化的,这是必须提供deleter模板参数的原因吗
  • 如果前面问题的答案是肯定的,那么如果通过从链接页面中的类模板参数推断选择了这两个构造函数中的任何一个,那么程序格式错误的句子是什么意思
  • \u Dp
    \u Del
    实际上有什么区别,这有什么重要意义
我想让我的头绕过它的尝试失败了 在这里,我试图解释我的推理。上面提到的一些问题也分散在文本中

我的理解是,在C++17之前的版本中,模板类型推断不适用于类,而仅适用于函数,因此在创建模板类的实例时,如
std::unique_ptr
,所有都是强制性的(即没有
=默认_type_或_值
)模板类的模板参数必须通过
提供

此外,在
/usr/include/c++/10.2.0/bits/unique_ptr.h
中,我或多或少看到了这一点:

名称空间std{
// …
模板
类唯一\u ptr{
公众:
// …
使用deleter\u type=\u Dp;
// …
模板
唯一的\u ptr(指针u p,常量deleter_类型&\uu d)无例外:_M_t(u p,u d){
// …
}
// …
}
其中,构造函数在类型参数
\u Del
上模板化,该参数默认为类“
deleter\u type
(它是
\u Dp
的别名);由此我了解到,如果我错了,请纠正我(*)
std::unique_ptr
甚至不能利用C++17对类的模板类型推断,因此就重载而言,
\u Dp
的模板参数仍然是强制的(即,如果要将deleter对象作为第二个参数传递给构造函数)

既然如此,我们传递给
std::unique\u ptr
的实际类型参数可以使用引用声明符进行修饰,如链接页面中所述。但这就是我迷失的地方,更不用说我确实看到通常
\u Dp
\u Del
可以不同(例如,它们可能因引用声明者的不同而不同),这使我的理解更加复杂

但是,我将复制页面中解释各种可能场景的部分:

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

  • a) 如果
    D
    为非参考类型
    a
    ,则签名为:

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

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

    unique_ptr(pointer p, const A& d) noexcept;
    unique_ptr(pointer p, A&& d) noexcept;
    
    unique_ptr(pointer p, A& d) noexcept;
    unique_ptr(pointer p, A&& d) = delete;
    
    unique_ptr(pointer p, const A& d) noexcept;
    unique_ptr(pointer p, const A&& d) = delete;
    
在所有情况下,删除程序都是从
std::forward(d)
初始化的。只有当
std::is_constructible::value
true
时,这些重载才参与重载解析

我能解释引用的文本的唯一方法是如下,带着很多疑问

  • 如果我们想将deleter
    d
    作为参数传递给构造函数,我们必须明确地将a
    d
    作为模板参数传递给。。。什么?到
    类和/或它的构造函数?甚至可以将模板参数传递给构造函数吗
  • D
    可以有三种
  • 如果我们将其指定为
    A
    ,这意味着我们希望能够将A(可能是
    const
    )左值或右值传递为
    d
    ,这样就定义了取
    const A&
    A&
    的两个重载
  • 如果我们将其指定为
    常量a&
    ,这意味着我们希望不能将右值作为
    d
    传递,因此使用
    a&
    的重载将被删除,因为它将绑定到右值,而使用
    常量a&
    的重载,因为后者也将绑定到右值
  • 如果我们将其指定为
    常量a&
    ,这意味着我们希望能够将左值或右值同时传递为
    d
    ,因此选择使用
    常量a&
    的重载,而使用
    常量a&
    的重载是
    删除,因为该参数类型无法绑定到左值,它对待右值的方式与
    常量A&
    的方式没有什么不同,正如答案中所解释的,最重要的是,它绑定到右值,防止另一个重载
    常量A&
    绑定到右值,这将导致悬挂引用存储在
    std::unique\u ptr
    中(原因如下)
  • 但是,1的不同用例是什么。三,。当右值作为
    d
    传递时?1.将其绑定到
    A&
    和3。将它绑定到
    常量A&
    ,这样前者可以窃取资源,而后者则不能
最后但并非最不重要的一点是,链接页面还添加了一些特定于C++17的内容:

如果通过类模板参数推断选择了这两个构造函数中的任何一个,则程序是格式错误的